{
 "cells": [
  {
   "cell_type": "markdown",
   "id": "cde85a81",
   "metadata": {},
   "source": [
    "## Reaction Basics"
   ]
  },
  {
   "cell_type": "markdown",
   "id": "0127e641",
   "metadata": {},
   "source": [
    "### 0. Install the necessary Python libraries"
   ]
  },
  {
   "cell_type": "code",
   "id": "5cc41693",
   "metadata": {
    "ExecuteTime": {
     "end_time": "2025-05-05T22:14:02.430823Z",
     "start_time": "2025-05-05T22:14:02.429184Z"
    }
   },
   "source": [
    "import sys\n",
    "IN_COLAB = 'google.colab' in sys.modules\n",
    "if IN_COLAB:\n",
    "    !pip install pandas rdkit mols2grid"
   ],
   "outputs": [],
   "execution_count": 1
  },
  {
   "cell_type": "markdown",
   "id": "07b4fa15",
   "metadata": {},
   "source": [
    "### 1. Introduction\n",
    "In this notebook we demonstrate a simple two-component library enumeration. We begin by sketching the reaction using the sketcher on the [Marvin JS Demo page](https://marvinjs-demo.chemaxon.com/latest/demo.html).  Once we've sketched the reaction, we will export the reaction as a **Reaction SMARTS** that can be processed by the RDKit. We will then look at how we can use that reaction SMARTS to enumerate a chemical library. A reaction SMARTS is similar to the SMARTS we saw in the previous notebook, with a couple of additions.  The reaction smarts consists of two parts separated by a reaction arrow, written as **\">>\"**. The part of the reaction SMARTS to the left of the reaction arrow represents the reactants and the part to the right represents the products.  The other difference from a typical SMARTS is the atom map numbers that follow the **\":\"** in the reaction SMARTS (shown in red in the figure below).  These specify the correspondence between reactant atoms and product atoms. Atom 1 in the reactants maps to atom 1 in the products, and so on.  By specifying reactions this way, we can transform a set of reactants into a reaction product. It's important to remember that reaction processing in the RDKit proceeds in two steps. \n",
    "1. The reaction smarts for the reactants are mapped to the supplied reactants. This enables the RDKit reaction object to determine which reactant atoms will be transformed to product atoms. As such, it is important to specify the number of hydrogens attached to heteroatoms in the reactants.  We'll go into this more below.  Notice the hydrogen counts on the oxygen and the nitrogen in the reactants (highlighted in yellow).  We will also discuss this more in subsequent sections. \n",
    "2. The atom mappings in the product are used to transform the reactants into products. \n",
    "\n",
    "<img src=\"https://raw.githubusercontent.com/PatWalters/practical_cheminformatics_tutorials/main/reaction/images/amiderxn_000.png\" alt=\"Drawing\" style=\"width: 800px;\"/>"
   ]
  },
  {
   "cell_type": "markdown",
   "id": "0507f9b9",
   "metadata": {},
   "source": [
    "### 2. Set Up the Reaction\n",
    "In this section, we'll sketch a reaction and export it as a Reaction SMARTS that can be used by the RDKit. We begin by using the [Marvin JS Demo page](https://marvinjs-demo.chemaxon.com/latest/demo.html) to sketch an amide reaction. Note that it's not necessary to put a \"+\" between the reactants. "
   ]
  },
  {
   "cell_type": "markdown",
   "id": "ea200f1d",
   "metadata": {},
   "source": [
    "<img src=\"https://raw.githubusercontent.com/PatWalters/practical_cheminformatics_tutorials/main/reaction/images/amiderxn_001.png\" alt=\"Drawing\" style=\"width: 600px;\"/>"
   ]
  },
  {
   "cell_type": "markdown",
   "id": "774a465f",
   "metadata": {},
   "source": [
    "Next we need to specify the hydrogen counts for any reactant heteroatoms with attached hydrogens.  This will improve the accuracy of the atom mapping.  For instance, the reaction above contains a carboxylic acid as a reactant.  We want our reaction to match carboxylic acids but not esters. We can do this by specifying that the acid oxygen has 1 attached hydrogen.  Similarly, if we want the primary amine in the reaction above to match primary amines and not secondary or tertiary amines, we can specify that the amine nitrogen must have 2 attached hydrogens. To specify the hydrogen counts do the following. \n",
    "1. Right click on the atom of interest. Try this with the carboxylic acid oxygen.\n",
    "2. Once you right click on an atom, you'll see a popup menu, select \"Atom properties\" from the menu. \n",
    "3. After the menu selection you'll see a dialog box like the one shown in the figure below. \n",
    "4. Click on the \"Advanced\" tab\n",
    "5. Click the lock icon to the right of the \"Total H (H)\" field \n",
    "6. Type \"1\" in the \"Total H (H)\" field. \n",
    "7. Click \"OK\""
   ]
  },
  {
   "cell_type": "markdown",
   "id": "2510d66f",
   "metadata": {},
   "source": [
    "<img src=\"https://raw.githubusercontent.com/PatWalters/practical_cheminformatics_tutorials/main/reaction/images/amiderxn_002.png\" alt=\"Drawing\" style=\"width: 300px;\"/>"
   ]
  },
  {
   "cell_type": "markdown",
   "id": "308bc1f9",
   "metadata": {},
   "source": [
    "Repeat the procedure above and specify \"Total H (H)\" as 2 for the amine nitrogen.  After this you should see a notation on each of the two atoms showing the allowed number of attached hydrogens. "
   ]
  },
  {
   "cell_type": "markdown",
   "id": "cbf3819e",
   "metadata": {},
   "source": [
    "<img src=\"https://raw.githubusercontent.com/PatWalters/practical_cheminformatics_tutorials/main/reaction/images/amiderxn_003.png\" alt=\"Drawing\" style=\"width: 600px;\"/>"
   ]
  },
  {
   "cell_type": "markdown",
   "id": "e70714f9",
   "metadata": {},
   "source": [
    "Next we click on the automap icon to map the atoms in the reactants to atoms in the product. "
   ]
  },
  {
   "cell_type": "markdown",
   "id": "4564b088",
   "metadata": {},
   "source": [
    "<img src=\"https://raw.githubusercontent.com/PatWalters/practical_cheminformatics_tutorials/main/reaction/images/amiderxn_004.png\" alt=\"Drawing\" style=\"width: 600px;\"/>"
   ]
  },
  {
   "cell_type": "markdown",
   "id": "9a9a0693",
   "metadata": {},
   "source": [
    "After mapping you'll see something like what's shown in the figure below. Note how the atom mapping establishes the correspondence between the reactant and product atom. Now each reactant atom is mapped to the corresponding product atoms. The hydroxyl oxygen, indicated by the arrow in the figure below, doesn't appear in the product. This atom has atom map number \"3\", but none of the product atoms have atom map number 3.  One important thing to remember about reactions in the RDKit is that **every mapped atom in the reactants must be mapped in the product**.  To use this reaction with the RDKit we need to remove atom map number 3.  Fortunately, this is easy to do."
   ]
  },
  {
   "cell_type": "markdown",
   "id": "1dedad5e",
   "metadata": {},
   "source": [
    "<img src=\"https://raw.githubusercontent.com/PatWalters/practical_cheminformatics_tutorials/main/reaction/images/amiderxn_006.png\" alt=\"Drawing\" style=\"width: 600px;\"/>"
   ]
  },
  {
   "cell_type": "markdown",
   "id": "ed05a3a9",
   "metadata": {},
   "source": [
    "To make our reaction compatible with the RDKit, we need to \"unmap\" the hydroxyl oxygen.  To do this, follow these steps. \n",
    "1. Right click on the hydroxyl oxygen and select \"Atom properties\" from the popup menu. \n",
    "2. Click the \"Advanced\" tab in the dialog box. \n",
    "3. Click the lock icon to the right of the \"Map\" field\n",
    "4. Change the value \"3\" to \"0\".  This will remove the map from the atom. \n",
    "5. Click \"Ok\""
   ]
  },
  {
   "cell_type": "markdown",
   "id": "b881313c",
   "metadata": {},
   "source": [
    "<img src=\"https://raw.githubusercontent.com/PatWalters/practical_cheminformatics_tutorials/main/reaction/images/amiderxn_007.png\" alt=\"Drawing\" style=\"width: 600px;\"/>"
   ]
  },
  {
   "cell_type": "markdown",
   "id": "7fc6f888",
   "metadata": {},
   "source": [
    "At this point, the MarvinJS window should look like the figure below. Note that the hydroxyl oxygen no longer has an atom map number. "
   ]
  },
  {
   "cell_type": "markdown",
   "id": "c0de597c",
   "metadata": {},
   "source": [
    "<img src=\"https://raw.githubusercontent.com/PatWalters/practical_cheminformatics_tutorials/main/reaction/images/amiderxn_008.png\" alt=\"Drawing\" style=\"width: 600px;\"/>"
   ]
  },
  {
   "cell_type": "markdown",
   "id": "30dbf542",
   "metadata": {},
   "source": [
    "We're almost there. All we have to do now is export the reaction as **SMARTS**.  To do this, click on the \"Export\" icon identified by the arrow in the figure below. "
   ]
  },
  {
   "cell_type": "markdown",
   "id": "4f11869a",
   "metadata": {},
   "source": [
    "<img src=\"https://raw.githubusercontent.com/PatWalters/practical_cheminformatics_tutorials/main/reaction/images/amiderxn_009.png\" alt=\"Drawing\" style=\"width: 600px;\"/>"
   ]
  },
  {
   "cell_type": "markdown",
   "id": "30c6290e",
   "metadata": {},
   "source": [
    "### 3. Get the Reaction as Reaction SMARTS\n",
    "Use the **\"Format\"** menu to set the format to **\"SMARTS\"** and copy the SMARTS to the clipboard. We can the paste the SMARTS into the code cell below. "
   ]
  },
  {
   "cell_type": "markdown",
   "id": "b4445906",
   "metadata": {},
   "source": [
    "<img src=\"https://raw.githubusercontent.com/PatWalters/practical_cheminformatics_tutorials/main/reaction/images/amiderxn_010.png\" alt=\"Drawing\" style=\"width: 500px;\"/>"
   ]
  },
  {
   "cell_type": "markdown",
   "id": "5831bfa9",
   "metadata": {},
   "source": [
    "Allright, we've finished the preliminaries.  Let's write some code!  We begin by importing the necessary Python libraries. "
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 1,
   "id": "be88387f",
   "metadata": {},
   "outputs": [],
   "source": [
    "from rdkit import Chem\n",
    "from rdkit.Chem import AllChem\n",
    "import pandas as pd\n",
    "import mols2grid\n",
    "from itertools import product"
   ]
  },
  {
   "cell_type": "markdown",
   "id": "0bc8095c",
   "metadata": {},
   "source": [
    "Assign a variable to the Reaction SMARTS we exported from MarvinJS."
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 2,
   "id": "84244379",
   "metadata": {},
   "outputs": [],
   "source": [
    "rxn_smarts = \"[#7H2:7]-[#6:9].[#8H]-[#6:1](-[#6:2])=[O:3]>>[#6:9]-[#7:7]-[#6:1](-[#6:2])=[O:3]\""
   ]
  },
  {
   "cell_type": "markdown",
   "id": "b0090a7c",
   "metadata": {},
   "source": [
    "Create an RDKit reaction molecule from the Reaction SMARTS. "
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 3,
   "id": "ed60a3b0",
   "metadata": {},
   "outputs": [
    {
     "data": {
      "image/png": "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",
      "text/plain": [
       "<rdkit.Chem.rdChemReactions.ChemicalReaction at 0x157c61cb0>"
      ]
     },
     "execution_count": 3,
     "metadata": {},
     "output_type": "execute_result"
    }
   ],
   "source": [
    "rxn_mol = AllChem.ReactionFromSmarts(rxn_smarts)\n",
    "rxn_mol"
   ]
  },
  {
   "cell_type": "markdown",
   "id": "c1f66227",
   "metadata": {},
   "source": [
    "### 4. Test the Reaction"
   ]
  },
  {
   "cell_type": "markdown",
   "id": "c5fbbb2e",
   "metadata": {},
   "source": [
    "Let's run a quick example to make sure our reaction works as expected.  We'll perform a simple reaction where we combine acetic acid with methylamine. **Note that the reactants must be in the same order specified in the reaction SMARTS.** If the reactants are not in the same order, you won't get a a reaction product. "
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 4,
   "id": "66a2b0f8",
   "metadata": {},
   "outputs": [
    {
     "data": {
      "image/png": "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",
      "text/plain": [
       "<rdkit.Chem.rdchem.Mol at 0x157c61f50>"
      ]
     },
     "execution_count": 4,
     "metadata": {},
     "output_type": "execute_result"
    }
   ],
   "source": [
    "acid_mol = Chem.MolFromSmiles(\"CC(=O)O\")\n",
    "acid_mol"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 5,
   "id": "22d74685",
   "metadata": {},
   "outputs": [
    {
     "data": {
      "image/png": "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",
      "text/plain": [
       "<rdkit.Chem.rdchem.Mol at 0x157c61ee0>"
      ]
     },
     "execution_count": 5,
     "metadata": {},
     "output_type": "execute_result"
    }
   ],
   "source": [
    "amine_mol = Chem.MolFromSmiles(\"CN\")\n",
    "amine_mol"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 6,
   "id": "946bdd6b",
   "metadata": {},
   "outputs": [
    {
     "data": {
      "image/png": "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",
      "text/plain": [
       "<rdkit.Chem.rdchem.Mol at 0x157c62180>"
      ]
     },
     "execution_count": 6,
     "metadata": {},
     "output_type": "execute_result"
    }
   ],
   "source": [
    "prods = rxn_mol.RunReactants([amine_mol, acid_mol])\n",
    "prods[0][0]"
   ]
  },
  {
   "cell_type": "markdown",
   "id": "37e37100",
   "metadata": {},
   "source": [
    "### 5. Enumerate a SMALL library\n",
    "Now we'll enumerate a library with 10 amines and 10 carboxylic acids.  We begin by reading the reagents from a file. "
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 7,
   "id": "26768d62",
   "metadata": {},
   "outputs": [
    {
     "data": {
      "text/html": [
       "<div>\n",
       "<style scoped>\n",
       "    .dataframe tbody tr th:only-of-type {\n",
       "        vertical-align: middle;\n",
       "    }\n",
       "\n",
       "    .dataframe tbody tr th {\n",
       "        vertical-align: top;\n",
       "    }\n",
       "\n",
       "    .dataframe thead th {\n",
       "        text-align: right;\n",
       "    }\n",
       "</style>\n",
       "<table border=\"1\" class=\"dataframe\">\n",
       "  <thead>\n",
       "    <tr style=\"text-align: right;\">\n",
       "      <th></th>\n",
       "      <th>SMILES</th>\n",
       "      <th>Name</th>\n",
       "      <th>Type</th>\n",
       "    </tr>\n",
       "  </thead>\n",
       "  <tbody>\n",
       "    <tr>\n",
       "      <th>0</th>\n",
       "      <td>N=C(N)NC[C@@H](N)C(=O)O</td>\n",
       "      <td>1576365</td>\n",
       "      <td>carboxylic_acid</td>\n",
       "    </tr>\n",
       "    <tr>\n",
       "      <th>1</th>\n",
       "      <td>CN(C)C[C@@H](N)C(=O)O</td>\n",
       "      <td>35024242</td>\n",
       "      <td>carboxylic_acid</td>\n",
       "    </tr>\n",
       "    <tr>\n",
       "      <th>2</th>\n",
       "      <td>Nc1nnn(CC(=O)O)n1</td>\n",
       "      <td>4294607</td>\n",
       "      <td>carboxylic_acid</td>\n",
       "    </tr>\n",
       "    <tr>\n",
       "      <th>3</th>\n",
       "      <td>COC(=O)[C@@H](O)CC(=O)O</td>\n",
       "      <td>14585673</td>\n",
       "      <td>carboxylic_acid</td>\n",
       "    </tr>\n",
       "    <tr>\n",
       "      <th>4</th>\n",
       "      <td>N=C(N)NC[C@H](N)C(=O)O</td>\n",
       "      <td>2384694</td>\n",
       "      <td>carboxylic_acid</td>\n",
       "    </tr>\n",
       "    <tr>\n",
       "      <th>5</th>\n",
       "      <td>N[C@H](CO)C(=O)O</td>\n",
       "      <td>895342</td>\n",
       "      <td>carboxylic_acid</td>\n",
       "    </tr>\n",
       "    <tr>\n",
       "      <th>6</th>\n",
       "      <td>NCC[C@H](N)C(=O)O</td>\n",
       "      <td>52986906</td>\n",
       "      <td>carboxylic_acid</td>\n",
       "    </tr>\n",
       "    <tr>\n",
       "      <th>7</th>\n",
       "      <td>C[C@@H](O)[C@H](N)C(=O)O</td>\n",
       "      <td>895103</td>\n",
       "      <td>carboxylic_acid</td>\n",
       "    </tr>\n",
       "    <tr>\n",
       "      <th>8</th>\n",
       "      <td>NC(=O)[C@H](N)CCC(=O)O</td>\n",
       "      <td>2560808</td>\n",
       "      <td>carboxylic_acid</td>\n",
       "    </tr>\n",
       "    <tr>\n",
       "      <th>9</th>\n",
       "      <td>NCC(=O)NCCC(=O)O</td>\n",
       "      <td>1637970</td>\n",
       "      <td>carboxylic_acid</td>\n",
       "    </tr>\n",
       "    <tr>\n",
       "      <th>10</th>\n",
       "      <td>CNC(=O)c1n[nH]c(N)n1</td>\n",
       "      <td>19844301</td>\n",
       "      <td>primary_amine</td>\n",
       "    </tr>\n",
       "    <tr>\n",
       "      <th>11</th>\n",
       "      <td>N=C(N)CN1CC[C@H](O)C1</td>\n",
       "      <td>203414649</td>\n",
       "      <td>primary_amine</td>\n",
       "    </tr>\n",
       "    <tr>\n",
       "      <th>12</th>\n",
       "      <td>COC[C@@H](O)CN</td>\n",
       "      <td>2263862</td>\n",
       "      <td>primary_amine</td>\n",
       "    </tr>\n",
       "    <tr>\n",
       "      <th>13</th>\n",
       "      <td>NC(=O)CN1CCOCC1</td>\n",
       "      <td>20436848</td>\n",
       "      <td>primary_amine</td>\n",
       "    </tr>\n",
       "    <tr>\n",
       "      <th>14</th>\n",
       "      <td>CNC(=S)NC(=N)N</td>\n",
       "      <td>33691246</td>\n",
       "      <td>primary_amine</td>\n",
       "    </tr>\n",
       "    <tr>\n",
       "      <th>15</th>\n",
       "      <td>N[C@H]1COC[C@@H]1O</td>\n",
       "      <td>12957834</td>\n",
       "      <td>primary_amine</td>\n",
       "    </tr>\n",
       "    <tr>\n",
       "      <th>16</th>\n",
       "      <td>CN(C)C[C@@H](N)C(=O)O</td>\n",
       "      <td>35024242</td>\n",
       "      <td>primary_amine</td>\n",
       "    </tr>\n",
       "    <tr>\n",
       "      <th>17</th>\n",
       "      <td>Nc1nnn(CC(=O)O)n1</td>\n",
       "      <td>4294607</td>\n",
       "      <td>primary_amine</td>\n",
       "    </tr>\n",
       "    <tr>\n",
       "      <th>18</th>\n",
       "      <td>NC(=O)c1ncc[nH]c1=O</td>\n",
       "      <td>8657</td>\n",
       "      <td>primary_amine</td>\n",
       "    </tr>\n",
       "    <tr>\n",
       "      <th>19</th>\n",
       "      <td>N[C@H](CO)C(=O)O</td>\n",
       "      <td>895342</td>\n",
       "      <td>primary_amine</td>\n",
       "    </tr>\n",
       "  </tbody>\n",
       "</table>\n",
       "</div>"
      ],
      "text/plain": [
       "                      SMILES       Name             Type\n",
       "0    N=C(N)NC[C@@H](N)C(=O)O    1576365  carboxylic_acid\n",
       "1      CN(C)C[C@@H](N)C(=O)O   35024242  carboxylic_acid\n",
       "2          Nc1nnn(CC(=O)O)n1    4294607  carboxylic_acid\n",
       "3    COC(=O)[C@@H](O)CC(=O)O   14585673  carboxylic_acid\n",
       "4     N=C(N)NC[C@H](N)C(=O)O    2384694  carboxylic_acid\n",
       "5           N[C@H](CO)C(=O)O     895342  carboxylic_acid\n",
       "6          NCC[C@H](N)C(=O)O   52986906  carboxylic_acid\n",
       "7   C[C@@H](O)[C@H](N)C(=O)O     895103  carboxylic_acid\n",
       "8     NC(=O)[C@H](N)CCC(=O)O    2560808  carboxylic_acid\n",
       "9           NCC(=O)NCCC(=O)O    1637970  carboxylic_acid\n",
       "10      CNC(=O)c1n[nH]c(N)n1   19844301    primary_amine\n",
       "11     N=C(N)CN1CC[C@H](O)C1  203414649    primary_amine\n",
       "12            COC[C@@H](O)CN    2263862    primary_amine\n",
       "13           NC(=O)CN1CCOCC1   20436848    primary_amine\n",
       "14            CNC(=S)NC(=N)N   33691246    primary_amine\n",
       "15        N[C@H]1COC[C@@H]1O   12957834    primary_amine\n",
       "16     CN(C)C[C@@H](N)C(=O)O   35024242    primary_amine\n",
       "17         Nc1nnn(CC(=O)O)n1    4294607    primary_amine\n",
       "18       NC(=O)c1ncc[nH]c1=O       8657    primary_amine\n",
       "19          N[C@H](CO)C(=O)O     895342    primary_amine"
      ]
     },
     "execution_count": 7,
     "metadata": {},
     "output_type": "execute_result"
    }
   ],
   "source": [
    "df = pd.read_csv(\"https://raw.githubusercontent.com/PatWalters/practical_cheminformatics_tutorials/main/reaction/data/amide_reagents.csv\")\n",
    "df"
   ]
  },
  {
   "cell_type": "markdown",
   "id": "a0a23c8b",
   "metadata": {},
   "source": [
    "Add a column to the dataframe with RDKit molecules."
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 8,
   "id": "ca88a952",
   "metadata": {},
   "outputs": [],
   "source": [
    "df['mol'] = df.SMILES.apply(Chem.MolFromSmiles)"
   ]
  },
  {
   "cell_type": "markdown",
   "id": "8e718114",
   "metadata": {},
   "source": [
    "Split the acids and amines into separate dataframes. "
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 9,
   "id": "6388959b",
   "metadata": {},
   "outputs": [],
   "source": [
    "acid_df = df.query(\"Type == 'carboxylic_acid'\").copy()\n",
    "amine_df = df.query(\"Type == 'primary_amine'\").copy()"
   ]
  },
  {
   "cell_type": "markdown",
   "id": "c3edff78",
   "metadata": {},
   "source": [
    "View the acids"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 10,
   "id": "f0dbc923",
   "metadata": {},
   "outputs": [
    {
     "data": {
      "application/vnd.jupyter.widget-view+json": {
       "model_id": "557b0b4bc72f423b8c09f52eba7f85e3",
       "version_major": 2,
       "version_minor": 0
      },
      "text/plain": [
       "MolGridWidget()"
      ]
     },
     "metadata": {},
     "output_type": "display_data"
    },
    {
     "data": {
      "text/html": [
       "<style>\n",
       "    /* Some CSS to integrate with Jupyter more cleanly */\n",
       "    div.output_subarea {\n",
       "        /* Undo an unfortunate max-width parameter\n",
       "        that causes the output area to be too narrow\n",
       "        on smaller screens. */\n",
       "        max-width: none;\n",
       "\n",
       "        /* Align the table with the content */\n",
       "        padding: 0;\n",
       "\n",
       "        /* Let it breathe */\n",
       "        margin-top: 20px;\n",
       "    }\n",
       "</style>\n",
       "\n",
       "<iframe class=\"mols2grid-iframe\" frameborder=\"0\" width=\"100%\"\n",
       "    \n",
       "    \n",
       "    allow=\"clipboard-write\"\n",
       "    \n",
       "    \n",
       "    sandbox=\"allow-scripts allow-same-origin allow-downloads allow-popups allow-modals\"\n",
       "    \n",
       "    srcdoc=\"\n",
       "\n",
       "\n",
       "\n",
       "&lt;html lang=&quot;en&quot;&gt;\n",
       "    &lt;head&gt;\n",
       "        &lt;meta charset=&quot;UTF-8&quot; /&gt;\n",
       "        &lt;meta http-equiv=&quot;X-UA-Compatible&quot; content=&quot;IE=edge&quot; /&gt;\n",
       "        &lt;meta name=&quot;viewport&quot; content=&quot;width=device-width, initial-scale=1.0&quot; /&gt;\n",
       "        &lt;title&gt;Document!&lt;/title&gt;\n",
       "\n",
       "\n",
       "\n",
       "        &lt;style&gt;\n",
       "            /**\n",
       " * General styling\n",
       " */\n",
       "body {\n",
       "    font-family: &#x27;DejaVu&#x27;, sans-serif;\n",
       "}\n",
       "h1,h2,h3,h4 {\n",
       "    margin: 0 0 10px 0;\n",
       "}\n",
       "h1 {\n",
       "    font-size: 26px;\n",
       "}\n",
       "h2 {\n",
       "    font-size: 20px;\n",
       "    font-weight: 400;\n",
       "}\n",
       "h3 {\n",
       "\tfont-size: 16px;\n",
       "}\n",
       "p {\n",
       "    margin: 0 0 10px 0;\n",
       "}\n",
       "\n",
       "\n",
       "/* Remove body margin inside iframe */\n",
       "body.m2g-inside-iframe {\n",
       "    margin: 0;\n",
       "}\n",
       "\n",
       "/* In-cell text */\n",
       "#mols2grid .data:not(.data-img) {\n",
       "    height: 16px;\n",
       "    line-height: 16px;\n",
       "}\n",
       "/* Text truncation */\n",
       "#mols2grid .data {\n",
       "    /* Break text into multiple lines (default for static)... */\n",
       "    word-wrap: normal;\n",
       "\n",
       "    /* ...or truncate it (default for interactive). */\n",
       "    overflow: hidden;\n",
       "    white-space: nowrap;\n",
       "    text-overflow: ellipsis;\n",
       "}\n",
       "\n",
       "\n",
       "/**\n",
       " * Popover\n",
       " * - - -\n",
       " * Note: this is a bootstrap variable which is not namespaced.\n",
       " * To avoid any contamination, we only style it when the\n",
       " * x-placement parameter is set.\n",
       " */\n",
       ".popover[x-placement] {\n",
       "    font-family: &#x27;DejaVu&#x27;, sans-serif;\n",
       "    background: white;\n",
       "    border: solid 1px rgba(0,0,0,.2);\n",
       "    font-size: 12px;\n",
       "    padding: 10px;\n",
       "    border-radius: 5px;\n",
       "    box-shadow: 0 0 20px rgba(0,0,0,.15);\n",
       "    user-select: none;\n",
       "}\n",
       ".popover[x-placement] h3 {\n",
       "    margin: 0;\n",
       "}\n",
       ".popover[x-placement] .arrow {\n",
       "    width: 10px;\n",
       "    height: 10px;\n",
       "    background: #fff;\n",
       "    border: solid 1px rgba(0,0,0,.2);\n",
       "    box-sizing: border-box;\n",
       "    position: absolute;\n",
       "    transform-origin: 5px 5px;\n",
       "    clip-path: polygon(0 0, 100% 0, 100% 100%);\n",
       "}\n",
       ".popover[x-placement=&#x27;left&#x27;] .arrow {\n",
       "    transform: rotate(45deg);\n",
       "    top: 50%;\n",
       "    right: -5px;\n",
       "}\n",
       ".popover[x-placement=&#x27;right&#x27;] .arrow {\n",
       "    transform: rotate(-135deg);\n",
       "    top: 50%;\n",
       "    left: -5px;\n",
       "}\n",
       ".popover[x-placement=&#x27;top&#x27;] .arrow {\n",
       "    transform: rotate(135deg);\n",
       "    left: 50%;\n",
       "    bottom: -5px;\n",
       "}\n",
       ".popover[x-placement=&#x27;bottom&#x27;] .arrow {\n",
       "    transform: rotate(-45deg);\n",
       "    left: 50%;\n",
       "    top: -5px;\n",
       "}\n",
       "            body {\n",
       "    /* Colors */\n",
       "    --m2g-black: rgba(0,0,0,.75);\n",
       "    --m2g-black-soft: rgba(0,0,0,.35);\n",
       "    --m2g-black-10: rgba(0,0,0,.1);\n",
       "    --m2g-bg: #f6f6f6;\n",
       "    --m2g-border: solid 1px rgba(0,0,0,0.2);\n",
       "    --m2g-hl: #555; /* Highlight color */\n",
       "    --m2g-hl-shadow: inset 0 0 0 1px var(--m2g-hl); /* Inset 1px shadow to make border thicker */\n",
       "    --m2g-blue: #0f62fe;\n",
       "    --m2g-blue-soft: rgba(15,98,254,.2);\n",
       "\n",
       "    /* Icons */\n",
       "    --m2g-icn-triangle: url(&#x27;data:image/svg+xml;utf8,&lt;svg width=&quot;20&quot; fill=&quot;rgba(0,0,0,.75)&quot; height=&quot;20&quot; viewBox=&quot;0 0 20 20&quot; xmlns=&quot;http://www.w3.org/2000/svg&quot;&gt;&lt;path d=&quot;M9.5713 13.285L6.2543 7.757C6.0543 7.424 6.2953 7 6.6823 7L13.3173 7C13.7053 7 13.9463 7.424 13.7453 7.757L10.4283 13.285C10.2343 13.609 9.7653 13.609 9.5713 13.285Z&quot;/&gt;&lt;/svg&gt;&#x27;);\n",
       "    --m2g-icn-triangle-white: url(&#x27;data:image/svg+xml;utf8,&lt;svg width=&quot;20&quot; fill=&quot;white&quot; height=&quot;20&quot; viewBox=&quot;0 0 20 20&quot; xmlns=&quot;http://www.w3.org/2000/svg&quot;&gt;&lt;path d=&quot;M9.5713 13.285L6.2543 7.757C6.0543 7.424 6.2953 7 6.6823 7L13.3173 7C13.7053 7 13.9463 7.424 13.7453 7.757L10.4283 13.285C10.2343 13.609 9.7653 13.609 9.5713 13.285Z&quot;/&gt;&lt;/svg&gt;&#x27;);\n",
       "    --m2g-icn-cb-white: url(&#x27;data:image/svg+xml;utf8,&lt;svg width=&quot;16&quot; height=&quot;16&quot; viewBox=&quot;0 0 16 16&quot; fill=&quot;none&quot; stroke=&quot;white&quot; stroke-width=&quot;2.5&quot; stroke-linecap=&quot;round&quot; xmlns=&quot;http://www.w3.org/2000/svg&quot;&gt;&lt;path d=&quot;M4 7.65686L7 10.6569L12.6569 5.00001&quot;/&gt;&lt;/svg&gt;&#x27;);\n",
       "    \n",
       "    /* Border radius */\n",
       "    --m2g-br: 3px;\n",
       "    --m2g-br-l: var(--m2g-br) 0 0 var(--m2g-br); /* Left-only */\n",
       "    --m2g-br-r: 0 var(--m2g-br) var(--m2g-br) 0; /* Right-only */\n",
       "\n",
       "    /* Text */\n",
       "    --m2g-fs: 14px; /* UI font-size */\n",
       "    --m2g-fs-cell: 12px; /* Cell font-size */\n",
       "\n",
       "    /* Transition speeds */\n",
       "    --m2g-trans: 150ms;\n",
       "\n",
       "    /* Layout */\n",
       "    --m2g-h: 40px; /* Form element height */\n",
       "}\n",
       "\n",
       "/* Styling */\n",
       "#mols2grid {\n",
       "    font-family: &#x27;DejaVu&#x27;, sans-serif;\n",
       "    font-size: var(--m2g-fs);\n",
       "}\n",
       "\n",
       "/* Fixes */\n",
       "#mols2grid *,\n",
       "#mols2grid *::before,\n",
       "#mols2grid *::after {\n",
       "    box-sizing: border-box;\n",
       "    outline: none;\n",
       "}\n",
       "\n",
       "\n",
       "\n",
       "/**\n",
       " * Functions section\n",
       " */\n",
       "\n",
       "#mols2grid .m2g-functions {\n",
       "    display: flex;\n",
       "}\n",
       "#mols2grid .m2g-functions .m2g-row {\n",
       "    flex: 0;\n",
       "    display: flex;\n",
       "}\n",
       "\n",
       "/* Individual elements don&#x27;t scale */\n",
       "#mols2grid .m2g-functions .m2g-row &gt; * {\n",
       "    flex: 0 0;\n",
       "    margin-right: 10px;\n",
       "}\n",
       "#mols2grid .m2g-functions .m2g-row:last-child &gt; *:last-child {\n",
       "    margin-right: 0;\n",
       "}\n",
       "\n",
       "/* Row 1: pagination + gap + sort */\n",
       "#mols2grid .m2g-functions .m2g-row:first-child {\n",
       "    flex: 1; /* Scale */\n",
       "}\n",
       "#mols2grid .m2g-functions .m2g-gap {\n",
       "    /* The gap in between will scale, so the pagination\n",
       "    stays on the left, while the rest moves to the right */\n",
       "    flex: 1;\n",
       "    margin-right: 0;\n",
       "}\n",
       "\n",
       "\n",
       "\n",
       "/*\n",
       " * Pagination\n",
       " */\n",
       "\n",
       "#mols2grid ul.m2g-pagination {\n",
       "    /* Unset defaults */\n",
       "    list-style-type: none;\n",
       "    margin-block-start: 0;\n",
       "    margin-block-end: 0;\n",
       "    margin-inline-start: 0;\n",
       "    margin-inline-end: 0;\n",
       "    padding-inline-start: 0;\n",
       "\n",
       "    /* Custom */\n",
       "    display: flex;\n",
       "}\n",
       "#mols2grid ul.m2g-pagination li {\n",
       "    background: var(--m2g-bg) ;\n",
       "    border: var(--m2g-border);\n",
       "    height: var(--m2g-h);\n",
       "    min-width: calc(var(--m2g-h) + 1px);\n",
       "    position: relative;\n",
       "    user-select: none;\n",
       "    \n",
       "    /* Compensate for double border */\n",
       "    margin-right: -1px;\n",
       "    \n",
       "    /* Center text */\n",
       "    display: flex;\n",
       "    align-items: center;\n",
       "    justify-content: center;\n",
       "}\n",
       "#mols2grid ul.m2g-pagination li:last-child {\n",
       "    min-width: var(--m2g-h);\n",
       "}\n",
       "#mols2grid ul.m2g-pagination li a {\n",
       "    text-decoration: none;\n",
       "    color: var(--m2g-black);\n",
       "    padding: 0 10px;\n",
       "    width: 100%;\n",
       "    height: var(--m2g-h);\n",
       "    line-height: var(--m2g-h);\n",
       "    text-align: center;\n",
       "    /* Compensate for border so there&#x27;s no gap between click areas  */\n",
       "    margin: 0 -1px;\n",
       "}\n",
       "\n",
       "/* Corner shape */\n",
       "#mols2grid ul.m2g-pagination li:first-child {\n",
       "    border-radius: var(--m2g-br-l);\n",
       "}\n",
       "#mols2grid ul.m2g-pagination li:last-child {\n",
       "    border-radius: var(--m2g-br-r);\n",
       "    margin-right: 0;\n",
       "}\n",
       "\n",
       "/* Focus state */\n",
       "#mols2grid ul.m2g-pagination li:focus-within {\n",
       "    border-color: var(--m2g-hl);\n",
       "    box-shadow: var(--m2g-hl-shadow);\n",
       "    z-index: 1;\n",
       "}\n",
       "\n",
       "/* Active state */\n",
       "#mols2grid ul.m2g-pagination li.active {\n",
       "    background: var(--m2g-hl);\n",
       "    z-index: 1;\n",
       "}\n",
       "#mols2grid ul.m2g-pagination li.active a {\n",
       "    cursor: default;\n",
       "    color: #fff;\n",
       "}\n",
       "\n",
       "/* Disabled sate */\n",
       "#mols2grid ul.m2g-pagination li.disabled a {\n",
       "    cursor: default;\n",
       "    color: rgba(0,0,0,.25);\n",
       "    pointer-events: none;\n",
       "}\n",
       "\n",
       "\n",
       "\n",
       "/*\n",
       " * Dropdowns\n",
       " */\n",
       "\n",
       "#mols2grid ::placeholder {\n",
       "    color: var(--m2g-black-soft);\n",
       "}\n",
       "#mols2grid .m2g-dropdown {\n",
       "    height: var(--m2g-h);\n",
       "    background: var(--m2g-bg);\n",
       "    border: var(--m2g-border);\n",
       "    border-radius: var(--m2g-br);\n",
       "    position: relative;\n",
       "}\n",
       "#mols2grid .m2g-dropdown select {\n",
       "    -webkit-appearance: none;\n",
       "    -moz-appearance: none;\n",
       "    -ms-appearance: none;\n",
       "    appearance: none;\n",
       "    background: transparent;\n",
       "    border: none;\n",
       "    height: 100%;\n",
       "    padding: 0 13px;\n",
       "    min-width: 0;\n",
       "    max-width: 250px;\n",
       "    color: var(--m2g-black);\n",
       "    cursor: pointer;\n",
       "}\n",
       "\n",
       "/* Icon */\n",
       "#mols2grid .m2g-dropdown .m2g-icon {\n",
       "    width: 30px;\n",
       "    height: var(--m2g-h);\n",
       "    display: flex;\n",
       "    align-items: center;\n",
       "    justify-content: center;\n",
       "    position: absolute;\n",
       "    top: 0;\n",
       "    right: 0;\n",
       "    pointer-events: none;\n",
       "}\n",
       "#mols2grid .m2g-dropdown .m2g-icon svg:not(.m2g-stroke) {\n",
       "    fill: var(--m2g-black);\n",
       "}\n",
       "#mols2grid .m2g-dropdown .m2g-icon svg.m2g-stroke {\n",
       "    stroke: var(--m2g-black);\n",
       "}\n",
       "\n",
       "/* Display */\n",
       "/* We hide the native select element because\n",
       " * it is limited in styling. Instead, we display\n",
       " * the selected value in a div. */\n",
       "#mols2grid .m2g-dropdown .m2g-display {\n",
       "    position: absolute;\n",
       "    left: 0;\n",
       "    right: 0;\n",
       "    top: 0;\n",
       "    bottom: 0;\n",
       "    pointer-events: none;\n",
       "    color: var(--m2g-black);\n",
       "    line-height: var(--m2g-h);\n",
       "    padding: 0 25px 0 13px;\n",
       "\n",
       "    /* Truncate dropdown text */\n",
       "    white-space: nowrap;\n",
       "\ttext-overflow: ellipsis;\n",
       "\toverflow: hidden;\n",
       "}\n",
       "\n",
       "/* Focus state */\n",
       "#mols2grid .m2g-dropdown:focus-within {\n",
       "    border-color: var(--m2g-hl);\n",
       "    box-shadow: var(--m2g-hl-shadow);\n",
       "}\n",
       "\n",
       "\n",
       "\n",
       "/**\n",
       " * Action dropdown\n",
       " */\n",
       "\n",
       "#mols2grid .m2g-dropdown.m2g-actions {\n",
       "    width: var(--m2g-h);\n",
       "    padding: 0;\n",
       "}\n",
       "#mols2grid .m2g-dropdown.m2g-actions select {\n",
       "    opacity: 0;\n",
       "    width: var(--m2g-h);\n",
       "}\n",
       "#mols2grid .m2g-dropdown.m2g-actions .m2g-icon {\n",
       "    width: var(--m2g-h);\n",
       "}\n",
       "\n",
       "\n",
       "\n",
       "/*\n",
       " * Sort dropdown\n",
       " */\n",
       "\n",
       "#mols2grid .m2g-dropdown.m2g-sort {\n",
       "    flex: 0 0 200px;\n",
       "    width: 200px; /* Needed in addition to flex-basis for small sizes! */\n",
       "    border-radius: var(--m2g-br);\n",
       "    background: var(--m2g-bg);\n",
       "    display: flex;\n",
       "}\n",
       "\n",
       "/* Dropdown */\n",
       "#mols2grid .m2g-dropdown.m2g-sort select {\n",
       "    flex: 1 1;\n",
       "    opacity: 0;\n",
       "    /* padding-right: 70px; Space for &quot;Sort:&quot; */\n",
       "    box-sizing: border-box;\n",
       "}\n",
       "\n",
       "/* Sort order */\n",
       "#mols2grid .m2g-dropdown.m2g-sort .m2g-order {\n",
       "    background: var(--m2g-bg) var(--m2g-icn-triangle) no-repeat center;\n",
       "    flex: 0 0 30px;\n",
       "    height: 100%;\n",
       "    border-left: var(--m2g-border);\n",
       "    cursor: pointer;\n",
       "}\n",
       "#mols2grid .m2g-dropdown.m2g-sort.m2d-arrow-desc .m2g-order {\n",
       "    transform: rotate(180deg);\n",
       "    border-left: none;\n",
       "    border-right: var(--m2g-border);\n",
       "}\n",
       "\n",
       "/* Display */\n",
       "#mols2grid .m2g-dropdown.m2g-sort .m2g-display {\n",
       "    right: 31px;\n",
       "    padding-right: 13px;\n",
       "}\n",
       "#mols2grid .m2g-dropdown.m2g-sort .m2g-display::before {\n",
       "    content: &#x27;Sort: &#x27;;\n",
       "}\n",
       "\n",
       "/* Focus state */\n",
       "#mols2grid .m2g-dropdown.m2g-sort:focus-within .m2g-display,\n",
       "#mols2grid .m2g-dropdown.m2g-sort:focus-within .m2g-order {\n",
       "    background-color: transparent;\n",
       "}\n",
       "\n",
       "\n",
       "\n",
       "/*\n",
       " * Search bar\n",
       " */\n",
       "\n",
       "#mols2grid .m2g-search-wrap {\n",
       "    height: var(--m2g-h);\n",
       "    display: flex;\n",
       "    align-items: center;\n",
       "    justify-content: flex-end;\n",
       "    background: var(--m2g-bg);\n",
       "    border: var(--m2g-border);\n",
       "    border-radius: var(--m2g-br);\n",
       "}\n",
       "#mols2grid .m2g-searchbar {\n",
       "    width: 170px;\n",
       "    height: var(--m2g-h);\n",
       "    padding: 0 13px;\n",
       "    border: none;\n",
       "    color: var(--m2g-black);\n",
       "    cursor: text;\n",
       "    background: transparent;\n",
       "}\n",
       "\n",
       "/* Focus state */\n",
       "#mols2grid .m2g-search-wrap:focus-within {\n",
       "    border-color: var(--m2g-hl);\n",
       "    box-shadow: var(--m2g-hl-shadow);\n",
       "}\n",
       "\n",
       "/* Option buttons */\n",
       "#mols2grid .m2g-search-options {\n",
       "    font-size: 12px;\n",
       "    display: flex;\n",
       "    height: calc(1.5em + .75rem);\n",
       "    line-height: calc(1.5em + .75rem);\n",
       "    margin-right: 5px;\n",
       "    border-radius: var(--m2g-br);\n",
       "    color: var(--m2g-black);\n",
       "}\n",
       "#mols2grid .m2g-search-options .m2g-option {\n",
       "    background: var(--m2g-black-10);\n",
       "    padding: 0 13px;\n",
       "    cursor: default;\n",
       "    user-select: none;\n",
       "}\n",
       "#mols2grid .m2g-search-options .m2g-option:not(.sel) {\n",
       "    cursor: pointer;\n",
       "}\n",
       "#mols2grid .m2g-search-options .m2g-option:first-child {\n",
       "    border-radius: 2px 0 0 2px;\n",
       "}\n",
       "#mols2grid .m2g-search-options .m2g-option:last-child {\n",
       "    border-radius: 0 2px 2px 0;\n",
       "}\n",
       "#mols2grid .m2g-search-options .m2g-option.sel {\n",
       "    background: var(--m2g-hl);\n",
       "    color: #fff;\n",
       "}\n",
       "\n",
       "\n",
       "\n",
       "/**\n",
       " * Grid\n",
       " */\n",
       "\n",
       "/* Container */\n",
       "#mols2grid .m2g-list {\n",
       "    display: flex;\n",
       "    flex-wrap: wrap;\n",
       "    align-items: flex-start;\n",
       "    justify-content: flex-start;\n",
       "    padding: 1px; /* Compensate for negative padding on cell */\n",
       "    user-select: none;\n",
       "    margin: 0px;\n",
       "    margin-top: 20px;\n",
       "    font-family: &#x27;DejaVu&#x27;, sans-serif;\n",
       "    \n",
       "}\n",
       "\n",
       "/* Cell */\n",
       "#mols2grid .m2g-cell {\n",
       "    border: 1px solid #cccccc;\n",
       "    text-align: center;\n",
       "    vertical-align: top;\n",
       "    font-family: var(--font-family);\n",
       "    padding: 10px;\n",
       "    padding-top: max(10px, 20px);\n",
       "    margin: -1px -1px 0 0;\n",
       "    flex: 1 0 130px;\n",
       "    position: relative;\n",
       "    font-size: var(--m2g-fs-cell);\n",
       "    cursor: pointer;\n",
       "    color: var(--m2g-black);\n",
       "    overflow: hidden;\n",
       "    box-sizing: border-box;\n",
       "    background-color: white;\n",
       "}\n",
       "#mols2grid .m2g-cell:focus {\n",
       "    z-index: 1;\n",
       "    border-color: var(--m2g-hl);\n",
       "    box-shadow: var(--m2g-hl-shadow);\n",
       "}\n",
       "\n",
       "/* Phantom cells to maintain grid structure with less results */\n",
       "#mols2grid .m2g-cell.m2g-phantom {\n",
       "    border: none;\n",
       "    pointer-events: none;\n",
       "    height: 0;\n",
       "    padding: 0;\n",
       "}\n",
       "\n",
       "/* Checkbox &amp; ID */\n",
       "#mols2grid .m2g-cb-wrap {\n",
       "    position: absolute;\n",
       "    top: 3px;\n",
       "    left: 3px;\n",
       "    display: flex;\n",
       "    border-radius: 2px;\n",
       "    font-size: 0;\n",
       "    line-height: 0;\n",
       "    padding: 3px;\n",
       "    padding-right: 0;\n",
       "}\n",
       "#mols2grid .m2g-cb-wrap input[type=checkbox] {\n",
       "    display: none;\n",
       "}\n",
       "#mols2grid .m2g-cb-wrap input[type=checkbox] + .m2g-cb {\n",
       "\twidth: 16px;\n",
       "\theight: 16px;\n",
       "\tbox-sizing: border-box;\n",
       "\tbackground: #fff;\n",
       "\tborder: var(--m2g-border);\n",
       "\tborder-radius: 2px;\n",
       "    margin-right: 5px;\n",
       "}\n",
       "#mols2grid .m2g-cb-wrap input[type=checkbox]:checked + .m2g-cb {\n",
       "    border: none;\n",
       "    background-color: var(--m2g-blue);\n",
       "    background-image: var(--m2g-icn-cb-white);\n",
       "}\n",
       "#mols2grid .m2g-tooltip {\n",
       "    /* This is a div spanning full cell size where the\n",
       "    tooltip is rendered around, because you can&#x27;t attach\n",
       "    it to the parent due to list.js limitation. */\n",
       "    width: 100%;\n",
       "    height: 100%;\n",
       "    position: absolute;\n",
       "    left: 0;\n",
       "    top: 0;\n",
       "    z-index: -1;\n",
       "    pointer-events: none;\n",
       "    opacity: 0;\n",
       "}\n",
       "#mols2grid .m2g-cell:has(:checked) {\n",
       "    background: #ffd !important; /* Overrides user-set background color */\n",
       "}\n",
       "#mols2grid .data-mols2grid-id-display {\n",
       "    font-size: var(--m2g-fs-cell);\n",
       "    line-height: 16px;\n",
       "}\n",
       "#mols2grid .m2g-cb-wrap input[type=checkbox] + .data-mols2grid-id-display {\n",
       "    padding: 0 5px 0 5px;\n",
       "}\n",
       "#mols2grid .m2g-cb-wrap .data-name-display {\n",
       "    font-size: var(--m2g-fs);\n",
       "    line-height: 16px;\n",
       "}\n",
       "\n",
       "/* Info + callback button wrap (28px high) */\n",
       "#mols2grid .m2g-cell-actions {\n",
       "    position: absolute;\n",
       "    top: 0;\n",
       "    right: 0;\n",
       "    display: flex;\n",
       "    flex-direction: row;\n",
       "    font-size: 0;\n",
       "    line-height: 0;\n",
       "    \n",
       "    /* background: yellow; */\n",
       "}\n",
       "\n",
       "/* Info button */\n",
       "#mols2grid .m2g-info {\n",
       "    width: 28px;\n",
       "    height: 28px;\n",
       "    border-radius: 2px;\n",
       "    line-height: 28px;\n",
       "    font-size: min(14px, 12px);\n",
       "    font-family: Georgia, serif;\n",
       "    font-style: italic;\n",
       "    padding: 0;\n",
       "    text-align: center;\n",
       "}\n",
       "#mols2grid .m2g-keep-tooltip .m2g-info {\n",
       "    color: #fff;\n",
       "}\n",
       "#mols2grid .m2g-keep-tooltip .m2g-info::before {\n",
       "    content: &#x27;i&#x27;;\n",
       "    width: 18px;\n",
       "    height: 18px;\n",
       "    line-height: 18px;\n",
       "    background: var(--m2g-hl);\n",
       "    position: absolute;\n",
       "    left: 5px;\n",
       "    top: 5px;\n",
       "    border-radius: 9px;\n",
       "}\n",
       "\n",
       "/* Callback button */\n",
       "#mols2grid .m2g-callback {\n",
       "    width: 28px;\n",
       "    height: 28px;\n",
       "    cursor: pointer;\n",
       "}\n",
       "#mols2grid .m2g-callback::after {\n",
       "    content: &#x27;&#x27;;\n",
       "    display: block;\n",
       "    width: 16px;\n",
       "    height: 16px;\n",
       "    margin: 6px;\n",
       "    border: var(--m2g-border);\n",
       "    border-radius: 2px;\n",
       "    background: var(--m2g-bg) var(--m2g-icn-triangle) no-repeat center;\n",
       "    transform: rotate(-90deg);\n",
       "}\n",
       "\n",
       "/* Image */\n",
       "#mols2grid .m2g-cell .data-img {\n",
       "    padding: 0;\n",
       "}\n",
       "#mols2grid .m2g-cell img,\n",
       "#mols2grid .m2g-cell svg {\n",
       "    max-width: 100%;\n",
       "    height: auto;\n",
       "    padding: 0;\n",
       "}\n",
       "#mols2grid .m2g-cell svg &gt; rect:first-child {\n",
       "    /* Remove the SVG background */\n",
       "    fill: transparent !important;\n",
       "}\n",
       "\n",
       "/* Text below image */\n",
       ".m2g-copy-blink {\n",
       "    animation: m2g-blink var(--m2g-trans) 3;\n",
       "}\n",
       "@keyframes m2g-blink {\n",
       "    0% {\n",
       "        opacity: 1;\n",
       "    }\n",
       "    49% {\n",
       "        opacity: 1;\n",
       "    }\n",
       "    50% {\n",
       "        opacity: 0;\n",
       "    }\n",
       "    100% {\n",
       "        opacity: 0;\n",
       "    }\n",
       "}\n",
       "\n",
       "/* Copyable text */\n",
       ".copy-me {\n",
       "    position: relative;\n",
       "    cursor: pointer;\n",
       "}\n",
       "\n",
       "\n",
       "\n",
       "/**\n",
       " * Modal popup\n",
       " * - - -\n",
       " * Triggered by make_popup_callback()\n",
       " * See https://mols2grid.readthedocs.io/en/latest/notebooks/callbacks.html#Display-a-popup-containing-descriptors\n",
       " */\n",
       "\n",
       "/* Container */\n",
       "#m2g-modal-container {\n",
       "    display: flex;\n",
       "    align-items: center;\n",
       "    justify-content: center;\n",
       "    background: var(--m2g-black-10);\n",
       "    position: fixed;\n",
       "    top: 0;\n",
       "    left: 0;\n",
       "    z-index: 1;\n",
       "    width: 100%;\n",
       "    height: 100%;\n",
       "    \n",
       "    /* Transition */\n",
       "    opacity: 0;\n",
       "    transition: opacity var(--m2g-trans) linear;\n",
       "}\n",
       "\n",
       "/* Modal */\n",
       "#m2g-modal {\n",
       "    background: #fff;\n",
       "    border-radius: var(--m2g-br);\n",
       "    box-shadow: 0 0 30px var(--m2g-black-10);\n",
       "    padding: 20px;\n",
       "    position: relative;\n",
       "    max-width: calc(100% - 80px);\n",
       "    max-height: calc(100% - 80px);\n",
       "    display: flex;\n",
       "    flex-direction: column;\n",
       "    min-width: 26px;\n",
       "\n",
       "    /* Transition */\n",
       "    opacity: 0;\n",
       "    transform: translate(0, 5px);\n",
       "    transition: transform var(--m2g-trans) ease-in-out, opacity var(--m2g-trans) linear;\n",
       "}\n",
       "#m2g-modal .m2g-modal-header {\n",
       "    flex: 0 0 26px;\n",
       "    margin-bottom: 10px;\n",
       "}\n",
       "#m2g-modal .m2g-modal-header h2 {\n",
       "    margin-bottom: 0;\n",
       "}\n",
       "#m2g-modal .m2g-modal-header h2 + p {\n",
       "    font-size: 15px;\n",
       "}\n",
       "#m2g-modal .m2g-modal-body {\n",
       "    flex: 1;\n",
       "    position: relative;\n",
       "}\n",
       "\n",
       "/* Transition */\n",
       "#m2g-modal-container.show {\n",
       "    opacity: 1;\n",
       "}\n",
       "#m2g-modal-container.show #m2g-modal {\n",
       "    opacity: 1;\n",
       "    transform: translate(0, 0);\n",
       "}\n",
       "\n",
       "/* Header + close btn */\n",
       "#m2g-modal h2 {\n",
       "    line-height: 26px;\n",
       "    padding-right: 40px;\n",
       "    text-transform: capitalize;\n",
       "}\n",
       "#m2g-modal h3 {\n",
       "    \n",
       "}\n",
       "#m2g-modal button.close {\n",
       "    background: transparent;\n",
       "    padding: 0;\n",
       "    color: var(--m2g-black);\n",
       "    font-size: 1.5rem;\n",
       "    width: 40px;\n",
       "    height: 40px;\n",
       "    position: absolute;\n",
       "    top: 13px;\n",
       "    right: 13px;\n",
       "    border: none;\n",
       "}\n",
       "\n",
       "/* Image */\n",
       "#m2g-modal .svg-wrap svg {\n",
       "    max-width: 100%;\n",
       "    margin-bottom: 20px;\n",
       "}\n",
       "\n",
       "/* Separator */\n",
       "hr {\n",
       "    width: 100%;\n",
       "    height: 1px;\n",
       "    background: #ddd;\n",
       "    margin: 15px 0;\n",
       "    border: none;\n",
       "}\n",
       "\n",
       "\n",
       "\n",
       "/**\n",
       " * Hover states\n",
       " */\n",
       "@media (hover:hover) {\n",
       "    /* Pagination */\n",
       "    #mols2grid ul.m2g-pagination li:not(.active):not(.disabled):hover {\n",
       "        background: #f0f0f0;\n",
       "        z-index: 1;\n",
       "    }\n",
       "    #mols2grid ul.m2g-pagination li.active + li:hover {\n",
       "        /* Keeping the hover border consiistent */\n",
       "        margin-left: 1px;\n",
       "        border-left: none;\n",
       "        min-width: 40px;\n",
       "    }\n",
       "\n",
       "    /* Dropdowns &amp; search */\n",
       "    #mols2grid .m2g-dropdown:not(:focus-within):hover,\n",
       "    #mols2grid .m2g-search-wrap:not(:focus-within):hover,\n",
       "    #mols2grid .m2g-sort:not(:focus-within) .m2g-order:hover {\n",
       "        background-color: #f0f0f0;\n",
       "    }\n",
       "    #mols2grid .m2g-search-wrap:not(:focus-within):hover {\n",
       "        background: #fff;\n",
       "        border-color: rgba(0,0,0,.3);\n",
       "    }\n",
       "    /* Hocus pocus to have separate hover states for dropdown and arrow */\n",
       "    #mols2grid .m2g-dropdown.m2g-sort:not(:focus-within):hover .m2g-order:not(:hover) + .m2g-display {\n",
       "        background-color: transparent;\n",
       "    }\n",
       "\n",
       "    /* Search options */\n",
       "    #mols2grid .m2g-search-options .m2g-option:not(.sel):hover {\n",
       "        background: rgba(0,0,0,.15);\n",
       "    }\n",
       "\n",
       "    /* Grid */\n",
       "    /* Note: this is in an ::after pseudo element, so the transparent\n",
       "    hover color plays nice with the cell background color. */\n",
       "    #mols2grid .m2g-cell:hover::after {\n",
       "        content: &#x27;&#x27;;\n",
       "        width: 100%;\n",
       "        height: 100%;\n",
       "        position: absolute;\n",
       "        top: 0;\n",
       "        left: 0;\n",
       "        background-color: rgba(0,0,0,0.05);\n",
       "        pointer-events: none;\n",
       "    }\n",
       "\n",
       "    /* info button */\n",
       "    #mols2grid .m2g-info:hover::before {\n",
       "        content: &#x27;i&#x27;;\n",
       "        color: #fff;\n",
       "        width: 18px;\n",
       "        height: 18px;\n",
       "        line-height: 18px;\n",
       "        background: var(--m2g-hl);\n",
       "        position: absolute;\n",
       "        left: 5px;\n",
       "        top: 5px;\n",
       "        border-radius: 9px;\n",
       "    }\n",
       "    \n",
       "    /* Callback button */\n",
       "    #mols2grid .m2g-callback:hover::after {\n",
       "        background-color: var(--m2g-black);\n",
       "        background-image: var(--m2g-icn-triangle-white);\n",
       "        border-color: transparent;\n",
       "    }\n",
       "\n",
       "    /* Copyable text */\n",
       "    .copy-me:hover {\n",
       "        text-decoration: underline;\n",
       "        text-decoration-color: var(--m2g-blue);\n",
       "    }\n",
       "}\n",
       "\n",
       "\n",
       "\n",
       "/**\n",
       " * Responsive behavior.\n",
       " * - - -\n",
       " * Note: container queries won&#x27;t work in older browsers,\n",
       " * but this is purely aesthetical behavior so that&#x27;s ok.\n",
       " * https://caniuse.com/css-container-queries\n",
       " */\n",
       "\n",
       "/* This sets the msg-list div as reference container */\n",
       "#mols2grid {\n",
       "    container-type: inline-size;\n",
       "}\n",
       "\n",
       "\n",
       "\n",
       "/**\n",
       " * Functions section\n",
       " */\n",
       "\n",
       "/* When there&#x27;s not enough space to put everything in one row, we break it into two.\n",
       " * - - -\n",
       " * 870px = pagination 280 + sort 200 + search 300 + menu 40 + (3*10 gap) = 850 + 20 buffer.\n",
       " * Buffer required because the button width inside the search depends on the font.\n",
       " */\n",
       "@container (max-width: 870px) {\n",
       "    #mols2grid .m2g-functions {\n",
       "        flex-direction: column-reverse;\n",
       "        gap: 10px;\n",
       "    }\n",
       "    #mols2grid .m2g-functions .m2g-row:last-child {\n",
       "        justify-content: flex-end;\n",
       "    }\n",
       "    #mols2grid .m2g-functions .m2g-row:first-child *:last-child {\n",
       "        margin-right: 0;\n",
       "    }\n",
       "}\n",
       "\n",
       "/* When there&#x27;s not enough room for pagination + sort on one row,\n",
       " * we reduce the sort drodpwon width.\n",
       " */\n",
       "@container (max-width: 500px) {\n",
       "    #mols2grid .m2g-functions .m2g-sort {\n",
       "        width: 80px;\n",
       "        flex-basis: 80px;\n",
       "    }\n",
       "    #mols2grid .m2g-functions .m2g-sort .m2g-display {\n",
       "        font-size: 0;\n",
       "        line-height: 0;\n",
       "        padding-right: 0;\n",
       "    }\n",
       "    #mols2grid .m2g-functions .m2g-sort .m2g-display::before {\n",
       "        content: &#x27;Sort&#x27;;\n",
       "        font-size: var(--m2g-fs);\n",
       "        line-height: var(--m2g-h);\n",
       "    }\n",
       "}\n",
       "\n",
       "/* When there&#x27;s not enough room for pagination + reduced sort on one row,\n",
       " * we reduce the pagination width.\n",
       " */\n",
       "@container (max-width: 500px) {\n",
       "    /* We&#x27;re overriding min-width from different\n",
       "    locations, including responsive rules */\n",
       "    #mols2grid ul.m2g-pagination li,\n",
       "    #mols2grid ul.m2g-pagination li:last-child,\n",
       "    #mols2grid ul.m2g-pagination li.active + li:hover {\n",
       "        min-width: 0;\n",
       "    }\n",
       "}\n",
       "\n",
       "/* When there&#x27;s not enough room for searchbar + menu\n",
       " * we scale down the searchbar to fit the container.\n",
       " */\n",
       "@container (max-width: 370px) {\n",
       "    #mols2grid .m2g-functions .m2g-row .m2g-search-wrap {\n",
       "        flex: 1;\n",
       "    }\n",
       "    #mols2grid .m2g-searchbar {\n",
       "        width: calc(100% - 50px);\n",
       "    }\n",
       "    #mols2grid .m2g-search-options {\n",
       "        width: 50px;\n",
       "    }\n",
       "\n",
       "    /* Collapse options in T/M buttons */\n",
       "    #mols2grid .m2g-search-options .m2g-option {\n",
       "        width: 25px;\n",
       "        text-align: center;\n",
       "        padding: 0;\n",
       "        overflow: hidden;\n",
       "    }\n",
       "    #mols2grid .m2g-search-options .m2g-option:first-child::before {\n",
       "        content: &#x27;T\\A&#x27;\n",
       "    }\n",
       "    #mols2grid .m2g-search-options .m2g-option:last-child::before {\n",
       "        content: &#x27;S\\A&#x27;\n",
       "    }\n",
       "}\n",
       "\n",
       "\n",
       "\n",
       "/**\n",
       " * Grid\n",
       " */\n",
       "\n",
       "/* When there&#x27;s room for 5 columns, fall back to 4 */\n",
       "@container (min-width: 519px) and (max-width: 779px) {\n",
       "    #mols2grid .m2g-cell {\n",
       "        flex-basis: calc(100% / 4);\n",
       "    }\n",
       "}\n",
       "\n",
       "/* When there&#x27;s room for 7-11 columns, fall back to 6 */\n",
       "@container (min-width: 779px) and (max-width: 1559px) {\n",
       "    #mols2grid .m2g-cell {\n",
       "        flex-basis: calc(100% / 6);\n",
       "    }\n",
       "}\n",
       "\n",
       "/* When there&#x27;s room for 13+ columns, fall back to 12 */\n",
       "@container (min-width: 1559px) {\n",
       "    #mols2grid .m2g-cell {\n",
       "        flex-basis: calc(100% / 12);\n",
       "    }\n",
       "}\n",
       "\n",
       "            /* Custom CSS */\n",
       "            \n",
       "        &lt;/style&gt;\n",
       "        &lt;script src=&quot;https://cdnjs.cloudflare.com/ajax/libs/list.js/2.3.1/list.min.js&quot;&gt;&lt;/script&gt;\n",
       "&lt;script src=&quot;https://code.jquery.com/jquery-3.6.0.min.js&quot; integrity=&quot;sha256-/xUj+3OJU5yExlq6GSYGSHk7tPXikynS7ogEvDej/m4=&quot; crossorigin=&quot;anonymous&quot;&gt;&lt;/script&gt;\n",
       "&lt;script src=&quot;https://unpkg.com/@rdkit/rdkit@2022.3.1/Code/MinimalLib/dist/RDKit_minimal.js&quot;&gt;&lt;/script&gt;\n",
       "        &lt;script&gt;\n",
       "    // Set iframe height to fit content.\n",
       "    function fitIframe(iframe) {\n",
       "        // Ignore when there&#x27;s no iframe\n",
       "        if (!iframe) return\n",
       "\n",
       "        // Only fit height when no specific height was given.\n",
       "        if (iframe.getAttribute(&#x27;height&#x27;)) return;\n",
       "\n",
       "        // Initial fit + refit whenever the window width changes.\n",
       "        _fit()\n",
       "        $(window).on(&#x27;resize&#x27;, function() {\n",
       "            if (window.innerWidth != window.prevInnerWidth) {\n",
       "                window.prevInnerWidth = window.innerWidth\n",
       "                _fit();\n",
       "            }\n",
       "        })\n",
       "\n",
       "        // Fit iframe height to content height.\n",
       "        function _fit() {\n",
       "            var height = iframe.contentDocument.body.scrollHeight + 18 + &#x27;px&#x27;;\n",
       "            iframe.style.height = height;\n",
       "        }\n",
       "    }\n",
       "&lt;/script&gt;\n",
       "\n",
       "&lt;!-- prettier-ignore --&gt;\n",
       "&lt;script src=&quot;https://cdn.jsdelivr.net/npm/bootstrap@4.6.0/dist/js/bootstrap.bundle.min.js&quot; integrity=&quot;sha384-Piv4xVNRyMGpqkS2by6br4gNJ7DXjqk09RmUpJ8jgGtD7zP9yug3goQfGII0yAns&quot; crossorigin=&quot;anonymous&quot;&gt;&lt;/script&gt;\n",
       "        \n",
       "        &lt;!-- Custom header --&gt;\n",
       "        \n",
       "\n",
       "\n",
       "\n",
       "\n",
       "    &lt;/head&gt;\n",
       "    &lt;body class=&quot;m2g-inside-iframe&quot;&gt;\n",
       "\n",
       "\n",
       "\n",
       "        &lt;div id=&quot;mols2grid&quot; class=&quot;grid-default&quot;&gt;\n",
       "            &lt;!-- Pagination &amp; search --&gt;\n",
       "            &lt;div class=&quot;m2g-functions&quot;&gt;\n",
       "                \n",
       "                &lt;div class=&quot;m2g-row&quot;&gt;\n",
       "                    &lt;!-- Pagination --&gt;\n",
       "                    &lt;ul class=&quot;m2g-pagination&quot; class=&quot;d-flex&quot;&gt;&lt;/ul&gt;\n",
       "                    &lt;div class=&quot;m2g-gap&quot;&gt;&lt;/div&gt;\n",
       "\n",
       "                    &lt;!-- Sort dropdown --&gt;\n",
       "                    &lt;div class=&quot;m2g-dropdown m2g-sort&quot;&gt;\n",
       "                        &lt;select&gt;\n",
       "                            \n",
       "                            \n",
       "                                \n",
       "                                \n",
       "                                \n",
       "                            &lt;option value=&quot;mols2grid-id&quot; selected&gt;Index&lt;/option&gt;\n",
       "                                \n",
       "                            \n",
       "                                \n",
       "                                \n",
       "                                \n",
       "                            &lt;option value=&quot;data-Name&quot;&gt;Name&lt;/option&gt;\n",
       "                                \n",
       "                            \n",
       "                            \n",
       "                            &lt;option value=&quot;checkbox&quot;&gt;Selected&lt;/option&gt;\n",
       "                            \n",
       "                        &lt;/select&gt;\n",
       "                        &lt;div class=&quot;m2g-order&quot;&gt;&lt;/div&gt;\n",
       "                        &lt;div class=&quot;m2g-display&quot;&gt;\n",
       "                            Index\n",
       "                        &lt;/div&gt;\n",
       "                    &lt;/div&gt;\n",
       "                &lt;/div&gt;\n",
       "                &lt;div class=&quot;m2g-row&quot;&gt;\n",
       "                    &lt;!-- Search bar --&gt;\n",
       "                    &lt;div class=&quot;m2g-search-wrap&quot;&gt;\n",
       "                        &lt;input\n",
       "                            type=&quot;text&quot;\n",
       "                            class=&quot;m2g-searchbar form-control&quot;\n",
       "                            placeholder=&quot;Search&quot;\n",
       "                            aria-label=&quot;Search&quot;\n",
       "                            aria-describedby=&quot;basic-addon1&quot;\n",
       "                        /&gt;\n",
       "                        &lt;div class=&quot;m2g-search-options&quot;&gt;\n",
       "                            &lt;div class=&quot;m2g-option m2g-search-text sel&quot;&gt;Text&lt;/div&gt;\n",
       "                            &lt;div class=&quot;m2g-option m2g-search-smarts&quot;&gt;SMARTS&lt;/div&gt;\n",
       "                        &lt;/div&gt;\n",
       "                    &lt;/div&gt;\n",
       "\n",
       "                    &lt;!-- Action dropdown --&gt;\n",
       "                    &lt;div class=&quot;m2g-dropdown m2g-actions&quot;&gt;\n",
       "                        &lt;select&gt;\n",
       "                            &lt;option hidden&gt;-&lt;/option&gt;\n",
       "                            &lt;option value=&quot;select-all&quot;&gt;Select all&lt;/option&gt;\n",
       "                            &lt;option value=&quot;select-matching&quot;&gt;Select matching&lt;/option&gt;\n",
       "                            &lt;option value=&quot;unselect-all&quot;&gt;Unselect all&lt;/option&gt;\n",
       "                            &lt;option value=&quot;invert&quot;&gt;Invert&lt;/option&gt;\n",
       "                            &lt;option value=&quot;copy&quot;&gt;Copy to clipboard&lt;/option&gt;\n",
       "                            &lt;option value=&quot;save-smiles&quot;&gt;Save SMILES&lt;/option&gt;\n",
       "                            &lt;option value=&quot;save-csv&quot;&gt;Save CSV&lt;/option&gt;\n",
       "                        &lt;/select&gt;\n",
       "                        &lt;div class=&quot;m2g-icon&quot;&gt;\n",
       "                            &lt;svg width=&quot;20&quot; height=&quot;20&quot; viewBox=&quot;0 0 20 20&quot; xmlns=&quot;http://www.w3.org/2000/svg&quot;&gt;\n",
       "                                &lt;path d=&quot;M11.5 4C11.5 4.82843 10.8284 5.5 10 5.5C9.17157 5.5 8.5 4.82843 8.5 4C8.5 3.17157 9.17157 2.5 10 2.5C10.8284 2.5 11.5 3.17157 11.5 4ZM11.5 10C11.5 10.8284 10.8284 11.5 10 11.5C9.17157 11.5 8.5 10.8284 8.5 10C8.5 9.17157 9.17157 8.5 10 8.5C10.8284 8.5 11.5 9.17157 11.5 10ZM10 17.5C10.8284 17.5 11.5 16.8284 11.5 16C11.5 15.1716 10.8284 14.5 10 14.5C9.17157 14.5 8.5 15.1716 8.5 16C8.5 16.8284 9.17157 17.5 10 17.5Z&quot;/&gt;\n",
       "                            &lt;/svg&gt;\n",
       "                        &lt;/div&gt;\n",
       "                    &lt;/div&gt;\n",
       "                &lt;/div&gt;\n",
       "            &lt;/div&gt;\n",
       "\n",
       "            &lt;!-- Grid --&gt;\n",
       "            \n",
       "            &lt;div class=&quot;m2g-list&quot;&gt;&lt;div class=&quot;m2g-cell&quot; data-mols2grid-id=&quot;0&quot; tabindex=&quot;0&quot;&gt;&lt;div class=&quot;m2g-cb-wrap&quot;&gt;&lt;input type=&quot;checkbox&quot; tabindex=&quot;-1&quot; class=&quot;position-relative float-left cached_checkbox&quot;&gt;&lt;div class=&quot;m2g-cb&quot;&gt;&lt;/div&gt;&lt;div class=&quot;data-mols2grid-id-display&quot;&gt;&lt;/div&gt;&lt;/div&gt;&lt;div class=&quot;m2g-cell-actions&quot;&gt;&lt;/div&gt;&lt;div class=&quot;data data-img copy-me&quot;&gt;&lt;/div&gt;&lt;div class=&quot;data data-Name copy-me&quot;&gt;&lt;/div&gt;&lt;div class=&quot;data data-SMILES copy-me&quot; style=&quot;display: none;&quot;&gt;&lt;/div&gt;&lt;/div&gt;&lt;/div&gt;\n",
       "        &lt;/div&gt;\n",
       "        &lt;script&gt;\n",
       "            // list.js\n",
       "var listObj = new List(&#x27;mols2grid&#x27;, {\n",
       "    listClass: &#x27;m2g-list&#x27;,\n",
       "    valueNames: [{data: [&#x27;mols2grid-id&#x27;]}, &#x27;data-SMILES&#x27;, &#x27;data-mols2grid-id&#x27;, &#x27;data-Name&#x27;, &#x27;data-img&#x27;, &#x27;data-mols2grid-id-display&#x27;],\n",
       "    item: &#x27;&lt;div class=&quot;m2g-cell&quot; data-mols2grid-id=&quot;0&quot; tabindex=&quot;0&quot;&gt;&lt;div class=&quot;m2g-cb-wrap&quot;&gt;&lt;input type=&quot;checkbox&quot; tabindex=&quot;-1&quot; class=&quot;position-relative float-left cached_checkbox&quot;&gt;&lt;div class=&quot;m2g-cb&quot;&gt;&lt;/div&gt;&lt;div class=&quot;data-mols2grid-id-display&quot;&gt;&lt;/div&gt;&lt;/div&gt;&lt;div class=&quot;m2g-cell-actions&quot;&gt;&lt;/div&gt;&lt;div class=&quot;data data-img copy-me&quot;&gt;&lt;/div&gt;&lt;div class=&quot;data data-Name copy-me&quot;&gt;&lt;/div&gt;&lt;div class=&quot;data data-SMILES copy-me&quot; style=&quot;display: none;&quot;&gt;&lt;/div&gt;&lt;/div&gt;&#x27;,\n",
       "    page: 24,\n",
       "    pagination: {\n",
       "        paginationClass: &quot;m2g-pagination&quot;,\n",
       "        item: &#x27;&lt;li class=&quot;page-item&quot;&gt;&lt;a class=&quot;page page-link&quot; href=&quot;#&quot; onclick=&quot;event.preventDefault()&quot;&gt;&lt;/a&gt;&lt;/li&gt;&#x27;,\n",
       "        innerWindow: 1,\n",
       "        outerWindow: 1,\n",
       "    },\n",
       "});\n",
       "listObj.remove(&quot;mols2grid-id&quot;, &quot;0&quot;);\n",
       "listObj.add([{&quot;data-SMILES&quot;: &quot;N=C(N)NC[C@@H](N)C(=O)O&quot;, &quot;mols2grid-id&quot;: 0, &quot;data-Name&quot;: 1576365, &quot;data-img&quot;: null, &quot;data-mols2grid-id-display&quot;: 0}, {&quot;data-SMILES&quot;: &quot;CN(C)C[C@@H](N)C(=O)O&quot;, &quot;mols2grid-id&quot;: 1, &quot;data-Name&quot;: 35024242, &quot;data-img&quot;: null, &quot;data-mols2grid-id-display&quot;: 1}, {&quot;data-SMILES&quot;: &quot;Nc1nnn(CC(=O)O)n1&quot;, &quot;mols2grid-id&quot;: 2, &quot;data-Name&quot;: 4294607, &quot;data-img&quot;: null, &quot;data-mols2grid-id-display&quot;: 2}, {&quot;data-SMILES&quot;: &quot;COC(=O)[C@@H](O)CC(=O)O&quot;, &quot;mols2grid-id&quot;: 3, &quot;data-Name&quot;: 14585673, &quot;data-img&quot;: null, &quot;data-mols2grid-id-display&quot;: 3}, {&quot;data-SMILES&quot;: &quot;N=C(N)NC[C@H](N)C(=O)O&quot;, &quot;mols2grid-id&quot;: 4, &quot;data-Name&quot;: 2384694, &quot;data-img&quot;: null, &quot;data-mols2grid-id-display&quot;: 4}, {&quot;data-SMILES&quot;: &quot;N[C@H](CO)C(=O)O&quot;, &quot;mols2grid-id&quot;: 5, &quot;data-Name&quot;: 895342, &quot;data-img&quot;: null, &quot;data-mols2grid-id-display&quot;: 5}, {&quot;data-SMILES&quot;: &quot;NCC[C@H](N)C(=O)O&quot;, &quot;mols2grid-id&quot;: 6, &quot;data-Name&quot;: 52986906, &quot;data-img&quot;: null, &quot;data-mols2grid-id-display&quot;: 6}, {&quot;data-SMILES&quot;: &quot;C[C@@H](O)[C@H](N)C(=O)O&quot;, &quot;mols2grid-id&quot;: 7, &quot;data-Name&quot;: 895103, &quot;data-img&quot;: null, &quot;data-mols2grid-id-display&quot;: 7}, {&quot;data-SMILES&quot;: &quot;NC(=O)[C@H](N)CCC(=O)O&quot;, &quot;mols2grid-id&quot;: 8, &quot;data-Name&quot;: 2560808, &quot;data-img&quot;: null, &quot;data-mols2grid-id-display&quot;: 8}, {&quot;data-SMILES&quot;: &quot;NCC(=O)NCCC(=O)O&quot;, &quot;mols2grid-id&quot;: 9, &quot;data-Name&quot;: 1637970, &quot;data-img&quot;: null, &quot;data-mols2grid-id-display&quot;: 9}]);\n",
       "\n",
       "\n",
       "// filter\n",
       "if (window.parent.mols2grid_lists === undefined) {\n",
       "    window.parent.mols2grid_lists = {};\n",
       "}\n",
       "window.parent.mols2grid_lists[&quot;default&quot;] = listObj;\n",
       "\n",
       "\n",
       "// selection\n",
       "class MolStorage extends Map {\n",
       "    multi_set(_id, _smiles) {\n",
       "        for (let i = 0; i &lt; _id.length; i++) {\n",
       "            this.set(_id[i], _smiles[i])\n",
       "        }\n",
       "    }\n",
       "    multi_del(_id) {\n",
       "        for (let i = 0; i &lt; _id.length; i++) {\n",
       "            this.delete(_id[i])\n",
       "        }\n",
       "    }\n",
       "    to_dict() {\n",
       "        var content = &#x27;{&#x27;\n",
       "        for (let [key, value] of this) {\n",
       "            content += key + &#x27;:&#x27; + JSON.stringify(value) + &#x27;,&#x27;\n",
       "        }\n",
       "        content = content.length &gt; 1 ? content.slice(0, -1) : content\n",
       "        content += &#x27;}&#x27;\n",
       "        return content\n",
       "    }\n",
       "    to_keys() {\n",
       "        var content = []\n",
       "        for (let [key] of this) {\n",
       "            content.push(key)\n",
       "        }\n",
       "        return content\n",
       "    }\n",
       "    download_smi(fileName, allItems) {\n",
       "        var content = &#x27;&#x27;\n",
       "\n",
       "        if (allItems) {\n",
       "            // Gather all smiles\n",
       "            for (var item of allItems) {\n",
       "                var smiles = item.values()[&#x27;data-SMILES&#x27;]\n",
       "                var id = item.values()[&#x27;mols2grid-id&#x27;]\n",
       "                content += smiles + &#x27; &#x27; + id + &#x27;\\n&#x27;\n",
       "            }\n",
       "        } else {\n",
       "            // Gather selected smiles\n",
       "            for (let [key, value] of this) {\n",
       "                content += value + &#x27; &#x27; + key + &#x27;\\n&#x27;\n",
       "            }\n",
       "        }\n",
       "\n",
       "        var a = document.createElement(&#x27;a&#x27;)\n",
       "        var file = new Blob([content], { type: &#x27;text/plain&#x27; })\n",
       "        a.href = URL.createObjectURL(file)\n",
       "        a.download = fileName\n",
       "        a.click()\n",
       "        a.remove()\n",
       "    }\n",
       "}\n",
       "var SELECTION = new MolStorage();\n",
       "\n",
       "\n",
       "\n",
       "// kernel\n",
       "function add_selection(grid_id, _id, smiles) {\n",
       "    SELECTION.multi_set(_id, smiles);\n",
       "    let model = window.parent[&quot;_MOLS2GRID_&quot; + grid_id];\n",
       "    if (model) {\n",
       "        model.set(&quot;selection&quot;, SELECTION.to_dict());\n",
       "        model.save_changes();\n",
       "    }\n",
       "}\n",
       "function del_selection(grid_id, _id) {\n",
       "    SELECTION.multi_del(_id);\n",
       "    let model = window.parent[&quot;_MOLS2GRID_&quot; + grid_id];\n",
       "    if (model) {\n",
       "        model.set(&quot;selection&quot;, SELECTION.to_dict());\n",
       "        model.save_changes();\n",
       "    }\n",
       "}\n",
       "if (window.parent.IPython !== undefined) {\n",
       "    // Jupyter notebook\n",
       "    var kernel_env = &quot;jupyter&quot;;\n",
       "} else if (window.parent.google !== undefined) {\n",
       "    // Google colab\n",
       "    var kernel_env = &quot;colab&quot;;\n",
       "} else {\n",
       "    var kernel_env = null;\n",
       "}\n",
       "\n",
       "\n",
       "\n",
       "\n",
       "// sort\n",
       "var sortField = &#x27;mols2grid-id&#x27;\n",
       "var sortOrder = &#x27;asc&#x27;\n",
       "\n",
       "// Sort dropdown\n",
       "$(&#x27;#mols2grid .m2g-sort select&#x27;).change(sort)\n",
       "\n",
       "// Sort order\n",
       "$(&#x27;#mols2grid .m2g-order&#x27;).click(flipSort)\n",
       "\n",
       "function sort(e) {\n",
       "    if (e) {\n",
       "        sortField = e.target.value\n",
       "        var selectedOption = e.target.options[e.target.selectedIndex]\n",
       "        var sortFieldDisplay = selectedOption.text\n",
       "    }\n",
       "\n",
       "    // Sort\n",
       "    if (sortField == &#x27;checkbox&#x27;) {\n",
       "        listObj.sort(&#x27;mols2grid-id&#x27;, {order: sortOrder, sortFunction: checkboxSort})\n",
       "    } else {\n",
       "        listObj.sort(sortField, {order: sortOrder, sortFunction: mols2gridSortFunction})\n",
       "    }\n",
       "\n",
       "    // Update UI.\n",
       "    $(this).parent().find(&#x27;.m2g-display&#x27;).text(sortFieldDisplay)\n",
       "}\n",
       "\n",
       "// prettier-ignore\n",
       "function flipSort() {\n",
       "    $(this).parent().removeClass(&#x27;m2d-arrow-&#x27; + sortOrder)\n",
       "    sortOrder = sortOrder === &#x27;desc&#x27; ? &#x27;asc&#x27; : &#x27;desc&#x27;\n",
       "    $(this).parent().addClass(&#x27;m2d-arrow-&#x27; + sortOrder)\n",
       "    sort()\n",
       "}\n",
       "\n",
       "function mols2gridSortFunction(itemA, itemB, options) {\n",
       "    var x = itemA.values()[options.valueName]\n",
       "    var y = itemB.values()[options.valueName]\n",
       "    if (typeof x === &#x27;number&#x27;) {\n",
       "        if (isFinite(x - y)) {\n",
       "            return x - y\n",
       "        } else {\n",
       "            return isFinite(x) ? -1 : 1\n",
       "        }\n",
       "    } else {\n",
       "        x = x ? x.toLowerCase() : x\n",
       "        y = y ? y.toLowerCase() : y\n",
       "        return x &lt; y ? -1 : x &gt; y ? 1 : 0\n",
       "    }\n",
       "}\n",
       "function checkboxSort(itemA, itemB, options) {\n",
       "    if (itemA.elm !== undefined) {\n",
       "        var checkedA = itemA.elm.querySelector(&#x27;input[type=checkbox]&#x27;).checked\n",
       "        if (itemB.elm !== undefined) {\n",
       "            var checkedB = itemB.elm.querySelector(&#x27;input[type=checkbox]&#x27;).checked\n",
       "            if (checkedA &amp;&amp; !checkedB) {\n",
       "                return -1\n",
       "            } else if (!checkedA &amp;&amp; checkedB) {\n",
       "                return 1\n",
       "            } else {\n",
       "                return 0\n",
       "            }\n",
       "        } else {\n",
       "            return -1\n",
       "        }\n",
       "    } else if (itemB.elm !== undefined) {\n",
       "        return 1\n",
       "    } else {\n",
       "        return 0\n",
       "    }\n",
       "}\n",
       "\n",
       "\n",
       "\n",
       "\n",
       "\n",
       "// grid interactions (select, click, tooltip, key events)\n",
       "// Check if selection UI is supported.\n",
       "var supportSelection = eval(&#x27;True&#x27;.toLowerCase());\n",
       "\n",
       "listObj.on(&quot;updated&quot;, initInteraction);\n",
       "\n",
       "// (Re)initialiuze all grid interaction every time the grid changes.\n",
       "function initInteraction(list) {\n",
       "    initCellClick()\n",
       "    initToolTip()\n",
       "    initKeyboard()\n",
       "    if (supportSelection) initCheckbox()\n",
       "\n",
       "\n",
       "    // Hide pagination if there is only one page.\n",
       "    if (listObj.matchingItems.length &lt;= listObj.page) {\n",
       "        $(&#x27;#mols2grid .m2g-pagination&#x27;).hide()\n",
       "    } else {\n",
       "        $(&#x27;#mols2grid .m2g-pagination&#x27;).show()\n",
       "    }\n",
       "\n",
       "    // Add a bunch of phantom cells.\n",
       "    // These are used as filler to make sure that\n",
       "    // no grid cells need to be resized when there&#x27;s\n",
       "    // not enough results to fill the row.\n",
       "    $(&#x27;#mols2grid .m2g-list&#x27;).append(&#x27;&lt;div class=&quot;m2g-cell m2g-phantom&quot;&gt;&lt;/div&gt;&#x27;.repeat(11));\n",
       "}\n",
       "\n",
       "// Cell click handler.\n",
       "function initCellClick() {\n",
       "    $(&#x27;#mols2grid .m2g-cell&#x27;).off(&#x27;click&#x27;).click(function(e) {\n",
       "        if ($(e.target).hasClass(&#x27;m2g-info&#x27;) || $(e.target).is(&#x27;:checkbox&#x27;)) {\n",
       "            // Info button / Checkbox --&gt; do nothing.\n",
       "        } else if ($(e.target).is(&#x27;div&#x27;) &amp;&amp; $(e.target).hasClass(&#x27;data&#x27;)) {\n",
       "            // Data string --&gt; copy text.\n",
       "            copyOnClick(e.target)\n",
       "        } else if ($(e.target).hasClass(&#x27;m2g-callback&#x27;)) {\n",
       "            // Callback button.\n",
       "            onCallbackButtonClick(e.target)\n",
       "        } else {\n",
       "            // Outside checkbox --&gt; toggle the checkbox.\n",
       "            if (supportSelection) {\n",
       "                var chkbox = $(this).find(&#x27;input:checkbox&#x27;)[0]\n",
       "                chkbox.checked = !chkbox.checked\n",
       "                $(chkbox).trigger(&#x27;change&#x27;)\n",
       "            }\n",
       "        }\n",
       "    })\n",
       "}\n",
       "\n",
       "// Store an element&#x27;s text content in the clipboard.\n",
       "function copyOnClick(target) {\n",
       "    var text = $(target).text()\n",
       "    navigator.clipboard.writeText(text)\n",
       "\n",
       "    // Blink the cell to indicate that the text was copied.\n",
       "    $(target).addClass(&#x27;m2g-copy-blink&#x27;)\n",
       "    setTimeout(function() {\n",
       "        $(target).removeClass(&#x27;m2g-copy-blink&#x27;)\n",
       "    }, 450)\n",
       "}\n",
       "\n",
       "// Keyboard actions.\n",
       "function initKeyboard() {\n",
       "    // Disable scroll when pressing UP/DOWN arrows\n",
       "    $(&#x27;#mols2grid .m2g-cell&#x27;).off(&#x27;keydown&#x27;).keydown(function(e) {\n",
       "        if (e.which == 38 || e.which == 40) {\n",
       "            e.preventDefault()\n",
       "        }\n",
       "    })\n",
       "\n",
       "    $(&#x27;#mols2grid .m2g-cell&#x27;).off(&#x27;keyup&#x27;).keyup(function(e) {\n",
       "        var chkbox = $(this).find(&#x27;input:checkbox&#x27;)[0]\n",
       "        if (e.which == 13) {\n",
       "            // ENTER: toggle\n",
       "            chkbox.checked = !chkbox.checked\n",
       "            $(chkbox).trigger(&#x27;change&#x27;)\n",
       "        } else if (e.which == 27 || e.which == 8) {\n",
       "            // ESC/BACKSPACE: unselect\n",
       "            chkbox.checked = false\n",
       "            $(chkbox).trigger(&#x27;change&#x27;)\n",
       "        } else if (e.which == 37) {\n",
       "            // LEFT\n",
       "            $(this).prev().focus()\n",
       "        } else if (e.which == 39) {\n",
       "            // RIGHT\n",
       "            $(this).next().focus()\n",
       "        } else if (e.which == 38 || e.which == 40) {\n",
       "            var containerWidth = $(this).parent().outerWidth()\n",
       "            var cellWidth = $(this).outerWidth() + parseInt($(this).css(&#x27;marginLeft&#x27;)) * 2\n",
       "            var columns = Math.round(containerWidth / cellWidth)\n",
       "            var index = $(this).index()\n",
       "            if (e.which == 38) {\n",
       "                // UP\n",
       "                var indexAbove = Math.max(index - columns, 0)\n",
       "                $(this).parent().children().eq(indexAbove).focus()\n",
       "            } else if (e.which == 40) {\n",
       "                // DOWN    \n",
       "                var total = $(this).parent().children().length\n",
       "                var indexBelow = Math.min(index + columns, total)\n",
       "                $(this).parent().children().eq(indexBelow).focus()\n",
       "            }\n",
       "        }\n",
       "    })\n",
       "}\n",
       "\n",
       "// Show tooltip when hovering the info icon.\n",
       "function initToolTip() {\n",
       "    $(&#x27;#mols2grid .m2g-info&#x27;).off(&#x27;mouseenter&#x27;).off(&#x27;mouseleave&#x27;).off(&#x27;click&#x27;).mouseenter(function() {\n",
       "        // Show on enter\n",
       "        $(this).closest(&#x27;.m2g-cell&#x27;).find(&#x27;.m2g-tooltip[data-toggle=&quot;popover&quot;]&#x27;).popover(&#x27;show&#x27;)\n",
       "        $(&#x27;body &gt; .popover&#x27;).click(function(e) {\n",
       "            if ($(e.target).hasClass(&#x27;copy-me&#x27;)) {\n",
       "                copyOnClick(e.target)\n",
       "            } else if ($(e.target).is(&#x27;button&#x27;)) {\n",
       "                \n",
       "            }\n",
       "        })\n",
       "    }).mouseleave(function() {\n",
       "        // Hide on leave, unless sticky.\n",
       "        if (!$(this).closest(&#x27;.m2g-cell&#x27;).hasClass(&#x27;m2g-keep-tooltip&#x27;)) {\n",
       "            $(this).closest(&#x27;.m2g-cell&#x27;).find(&#x27;.m2g-tooltip[data-toggle=&quot;popover&quot;]&#x27;).popover(&#x27;hide&#x27;)\n",
       "        }\n",
       "    }).click(function() {\n",
       "        // Toggle sticky on click.\n",
       "        $(this).closest(&#x27;.m2g-cell&#x27;).toggleClass(&#x27;m2g-keep-tooltip&#x27;)\n",
       "\n",
       "        // Hide tooltip when sticky was turned off.\n",
       "        if ($(this).closest(&#x27;.m2g-cell&#x27;).hasClass(&#x27;m2g-keep-tooltip&#x27;)) {\n",
       "            $(this).closest(&#x27;.m2g-cell&#x27;).find(&#x27;.m2g-tooltip[data-toggle=&quot;popover&quot;]&#x27;).popover(&#x27;show&#x27;)\n",
       "        } else if (!$(this).closest(&#x27;.m2g-cell&#x27;).hasClass(&#x27;m2g-keep-tooltip&#x27;)) {\n",
       "            $(this).closest(&#x27;.m2g-cell&#x27;).find(&#x27;.m2g-tooltip[data-toggle=&quot;popover&quot;]&#x27;).popover(&#x27;hide&#x27;)\n",
       "        }\n",
       "    })\n",
       "}\n",
       "\n",
       "// Update selection on checkbox click.\n",
       "function initCheckbox() {\n",
       "    $(&quot;input:checkbox&quot;).off(&#x27;change&#x27;).change(function() {\n",
       "        var _id = parseInt($(this).closest(&quot;.m2g-cell&quot;).attr(&quot;data-mols2grid-id&quot;));\n",
       "        if (this.checked) {\n",
       "            var _smiles = $($(this).closest(&quot;.m2g-cell&quot;).children(&quot;.data-SMILES&quot;)[0]).text();\n",
       "            add_selection(&quot;default&quot;, [_id], [_smiles]);\n",
       "        } else {\n",
       "            del_selection(&quot;default&quot;, [_id]);\n",
       "        }\n",
       "    });\n",
       "}\n",
       "\n",
       "// Callback button\n",
       "function onCallbackButtonClick(target) {\n",
       "    var data = {}\n",
       "    data[&quot;mols2grid-id&quot;] = parseInt($(target).closest(&quot;.m2g-cell&quot;)\n",
       "                                            .attr(&quot;data-mols2grid-id&quot;));\n",
       "    data[&quot;img&quot;] = $(target).parent().siblings(&quot;.data-img&quot;).eq(0).get(0).innerHTML;\n",
       "    $(target).parent().siblings(&quot;.data&quot;).not(&quot;.data-img&quot;).each(function() {\n",
       "        let name = this.className.split(&quot; &quot;)\n",
       "            .filter(cls =&gt; cls.startsWith(&quot;data-&quot;))[0]\n",
       "            .substring(5);\n",
       "        data[name] = this.innerHTML;\n",
       "    });\n",
       "\n",
       "    \n",
       "    // Call custom js callback.\n",
       "    None\n",
       "    \n",
       "}\n",
       "\n",
       "\n",
       "\n",
       "/**\n",
       " * Actions\n",
       " */\n",
       "\n",
       "// Listen to action dropdown.\n",
       "$(&#x27;#mols2grid .m2g-actions select&#x27;).change(function(e) {\n",
       "    var val = e.target.value\n",
       "    switch(val) {\n",
       "        case &#x27;select-all&#x27;:\n",
       "            selectAll()\n",
       "            break\n",
       "        case &#x27;select-matching&#x27;:\n",
       "            selectMatching()\n",
       "            break\n",
       "        case &#x27;unselect-all&#x27;:\n",
       "            unselectAll()\n",
       "            break\n",
       "        case &#x27;invert&#x27;:\n",
       "            invertSelection()\n",
       "            break\n",
       "        case &#x27;copy&#x27;:\n",
       "            copy()\n",
       "            break\n",
       "        case &#x27;save-smiles&#x27;:\n",
       "            saveSmiles()\n",
       "            break\n",
       "        case &#x27;save-csv&#x27;:\n",
       "            saveCSV()\n",
       "            break\n",
       "    }\n",
       "    $(this).val(&#x27;&#x27;) // Reset dropdown\n",
       "})\n",
       "\n",
       "// Check all.\n",
       "function selectAll(e) {\n",
       "    var _id = [];\n",
       "    var _smiles = [];\n",
       "    listObj.items.forEach(function (item) {\n",
       "        if (item.elm) {\n",
       "            item.elm.getElementsByTagName(&quot;input&quot;)[0].checked = true;\n",
       "        } else {\n",
       "            item.show()\n",
       "            item.elm.getElementsByTagName(&quot;input&quot;)[0].checked = true;\n",
       "            item.hide()\n",
       "        }\n",
       "        _id.push(item.values()[&quot;mols2grid-id&quot;]);\n",
       "        _smiles.push(item.values()[&quot;data-SMILES&quot;]);\n",
       "    });\n",
       "    add_selection(&quot;default&quot;, _id, _smiles);\n",
       "};\n",
       "\n",
       "\n",
       "// Check matching.\n",
       "function selectMatching(e) {\n",
       "    var _id = [];\n",
       "    var _smiles = [];\n",
       "    listObj.matchingItems.forEach(function (item) {\n",
       "        if (item.elm) {\n",
       "            item.elm.getElementsByTagName(&quot;input&quot;)[0].checked = true;\n",
       "        } else {\n",
       "            item.show()\n",
       "            item.elm.getElementsByTagName(&quot;input&quot;)[0].checked = true;\n",
       "            item.hide()\n",
       "        }\n",
       "        _id.push(item.values()[&quot;mols2grid-id&quot;]);\n",
       "        _smiles.push(item.values()[&quot;data-SMILES&quot;]);\n",
       "    });\n",
       "    add_selection(&quot;default&quot;, _id, _smiles);\n",
       "};\n",
       "\n",
       "// Uncheck all.\n",
       "function unselectAll(e) {\n",
       "    var _id = [];\n",
       "    listObj.items.forEach(function (item) {\n",
       "        if (item.elm) {\n",
       "            item.elm.getElementsByTagName(&quot;input&quot;)[0].checked = false;\n",
       "        } else {\n",
       "            item.show()\n",
       "            item.elm.getElementsByTagName(&quot;input&quot;)[0].checked = false;\n",
       "            item.hide()\n",
       "        }\n",
       "        _id.push(item.values()[&quot;mols2grid-id&quot;]);\n",
       "    });\n",
       "    del_selection(&quot;default&quot;, _id);\n",
       "};\n",
       "\n",
       "// Invert selection.\n",
       "function invertSelection(e) {\n",
       "    var _id_add = [];\n",
       "    var _id_del = [];\n",
       "    var _smiles = [];\n",
       "    listObj.items.forEach(function (item) {\n",
       "        if (item.elm) {\n",
       "            var chkbox = item.elm.getElementsByTagName(&quot;input&quot;)[0]\n",
       "            chkbox.checked = !chkbox.checked;\n",
       "        } else {\n",
       "            item.show()\n",
       "            var chkbox = item.elm.getElementsByTagName(&quot;input&quot;)[0]\n",
       "            chkbox.checked = !chkbox.checked;\n",
       "            item.hide()\n",
       "        }\n",
       "        if (chkbox.checked) {\n",
       "            _id_add.push(item.values()[&quot;mols2grid-id&quot;]);\n",
       "            _smiles.push(item.values()[&quot;data-SMILES&quot;]);\n",
       "        } else {\n",
       "            _id_del.push(item.values()[&quot;mols2grid-id&quot;]);\n",
       "        }\n",
       "    });\n",
       "    del_selection(&quot;default&quot;, _id_del);\n",
       "    add_selection(&quot;default&quot;, _id_add, _smiles);\n",
       "};\n",
       "\n",
       "// Copy to clipboard.\n",
       "function copy(e) {\n",
       "    // navigator.clipboard.writeText(SELECTION.to_dict());\n",
       "    content = _renderCSV(&#x27;\\t&#x27;)\n",
       "    navigator.clipboard.writeText(content)\n",
       "};\n",
       "\n",
       "// Export smiles.\n",
       "function saveSmiles(e) {\n",
       "    var fileName = &quot;selection.smi&quot;\n",
       "    if (SELECTION.size) {\n",
       "        // Download selected smiles\n",
       "        SELECTION.download_smi(fileName);\n",
       "    } else {\n",
       "        // Download all smiles\n",
       "        SELECTION.download_smi(fileName, listObj.items);\n",
       "    }\n",
       "};\n",
       "\n",
       "// Export CSV.\n",
       "function saveCSV(e) {\n",
       "    content = _renderCSV(&#x27;;&#x27;)\n",
       "    var a = document.createElement(&quot;a&quot;);\n",
       "    var file = new Blob([content], {type: &quot;text/csv&quot;});\n",
       "    a.href = URL.createObjectURL(file);\n",
       "    a.download = &quot;selection.csv&quot;;\n",
       "    a.click();\n",
       "    a.remove();\n",
       "};\n",
       "\n",
       "// Render CSV for export of clipboard.\n",
       "function _renderCSV(sep) {\n",
       "    // Same order as subset + tooltip\n",
       "    var columns = Array.from(listObj.items[0].elm.querySelectorAll(&quot;div.data&quot;))\n",
       "        .map(elm =&gt; elm.classList[1])\n",
       "        .filter(name =&gt; name !== &quot;data-img&quot;);\n",
       "    // Remove &#x27;data-&#x27; and img\n",
       "    var header = columns.map(name =&gt; name.slice(5));\n",
       "    // CSV content\n",
       "    header = [&quot;index&quot;].concat(header).join(sep);\n",
       "    var content = header + &quot;\\n&quot;;\n",
       "    listObj.items.forEach(function (item) {\n",
       "        let data = item.values();\n",
       "        let index = data[&quot;mols2grid-id&quot;];\n",
       "        if (SELECTION.has(index) || SELECTION.size === 0) {\n",
       "            content += index;\n",
       "            columns.forEach((key) =&gt; {\n",
       "                content += sep + data[key];\n",
       "            })\n",
       "            content += &quot;\\n&quot;;\n",
       "        }\n",
       "    });\n",
       "    return content\n",
       "}\n",
       "\n",
       "\n",
       "// generate images for the currently displayed molecules\n",
       "var draw_opts = {&quot;width&quot;: 130, &quot;height&quot;: 90};\n",
       "var json_draw_opts = JSON.stringify(draw_opts);\n",
       "\n",
       "var smarts_matches = {};\n",
       "\n",
       "// Load RDKit\n",
       "window\n",
       ".initRDKitModule()\n",
       ".then(function(RDKit) {\n",
       "    console.log(&#x27;RDKit version: &#x27;, RDKit.version());\n",
       "    window.RDKit = RDKit;\n",
       "    window.RDKitModule = RDKit;\n",
       "\n",
       "    // Searchbar\n",
       "    function SmartsSearch(query, columns) {\n",
       "    var smiles_col = columns[0];\n",
       "    smarts_matches = {};\n",
       "    var query = $(&#x27;#mols2grid .m2g-searchbar&#x27;).val();\n",
       "    var qmol = RDKit.get_qmol(query);\n",
       "    if (qmol.is_valid()) {\n",
       "        listObj.items.forEach(function (item) {\n",
       "            var smiles = item.values()[smiles_col]\n",
       "            var mol = RDKit.get_mol(smiles, &#x27;{&quot;removeHs&quot;: false }&#x27;);\n",
       "            if (mol.is_valid()) {\n",
       "                var results = mol.get_substruct_matches(qmol);\n",
       "                if (results === &quot;\\{\\}&quot;) {\n",
       "                    item.found = false;\n",
       "                } else {\n",
       "                    item.found = true;\n",
       "                    \n",
       "                    results = JSON.parse(results);\n",
       "                    \n",
       "                    var highlights = {&quot;atoms&quot;: [], &quot;bonds&quot;: []};\n",
       "                    results.forEach(function (match) {\n",
       "                        highlights[&quot;atoms&quot;].push(...match.atoms)\n",
       "                        highlights[&quot;bonds&quot;].push(...match.bonds)\n",
       "                    });\n",
       "                    \n",
       "                    var index = item.values()[&quot;mols2grid-id&quot;];\n",
       "                    smarts_matches[index] = highlights;\n",
       "                    \n",
       "                }\n",
       "            } else {\n",
       "                item.found = false;\n",
       "            }\n",
       "            mol.delete();\n",
       "        });\n",
       "    }\n",
       "    qmol.delete();\n",
       "}\n",
       "var search_type = &quot;Text&quot;;\n",
       "// Temporary fix for regex characters being escaped by list.js\n",
       "// This extends String.replace to ignore the regex pattern used by list.js and returns\n",
       "// the string unmodified. Other calls should not be affected, unless they use the exact\n",
       "// same pattern and replacement value.\n",
       "// TODO: remove once the issue is fixed in list.js and released\n",
       "String.prototype.replace = (function(_super) {\n",
       "    return function() {\n",
       "        if (\n",
       "            (arguments[0].toString() === &#x27;/[-[\\\\]{}()*+?.,\\\\\\\\^$|#]/g&#x27;)\n",
       "            &amp;&amp; (arguments[1] === &#x27;\\\\$&amp;&#x27;)\n",
       "        ) {\n",
       "            if (this.length === 0) {\n",
       "                return &#x27;&#x27;\n",
       "            }\n",
       "            return this\n",
       "        }\n",
       "        return _super.apply(this, arguments);\n",
       "    };         \n",
       "})(String.prototype.replace);\n",
       "\n",
       "// Switch search type (Text or SMARTS)\n",
       "$(&#x27;#mols2grid .m2g-search-options .m2g-option&#x27;).click(function() {\n",
       "    search_type = $(this).text();\n",
       "    $(&#x27;#mols2grid .m2g-search-options .m2g-option.sel&#x27;).removeClass(&quot;sel&quot;);\n",
       "    $(this).addClass(&quot;sel&quot;);\n",
       "});\n",
       "\n",
       "// Searchbar update event handler\n",
       "$(&#x27;#mols2grid .m2g-searchbar&#x27;).on(&quot;keyup&quot;, function(e) {\n",
       "    var query = e.target.value;\n",
       "    if (search_type === &quot;Text&quot;) {\n",
       "        smarts_matches = {};\n",
       "        listObj.search(query, [&#x27;data-mols2grid-id&#x27;, &#x27;data-Name&#x27;]);\n",
       "    } else {\n",
       "        listObj.search(query, [&quot;data-SMILES&quot;], SmartsSearch);\n",
       "    }\n",
       "});\n",
       "\n",
       "    \n",
       "    // Generate images for the currently displayed molecules.\n",
       "RDKit.prefer_coordgen(true);\n",
       "function draw_mol(smiles, index, template_mol) {\n",
       "    var mol = RDKit.get_mol(smiles, &#x27;{&quot;removeHs&quot;: false }&#x27;);\n",
       "    var svg = &quot;&quot;;\n",
       "    if (mol.is_valid()) {\n",
       "        var highlights = smarts_matches[index];\n",
       "        if (highlights) {\n",
       "            var details = Object.assign({}, draw_opts, highlights);\n",
       "            details = JSON.stringify(details);\n",
       "            mol.generate_aligned_coords(template_mol, true);\n",
       "        } else {\n",
       "            var details = json_draw_opts;\n",
       "        }\n",
       "        svg = mol.get_svg_with_highlights(details);\n",
       "    }\n",
       "    mol.delete();\n",
       "    if (svg == &quot;&quot;) {\n",
       "        return &#x27;&lt;svg width=&quot;130&quot; height=&quot;90&quot; xmlns=&quot;http://www.w3.org/2000/svg&quot; version=&quot;1.1&quot; viewBox=&quot;0 0 130 90&quot;&gt;&lt;/svg&gt;&#x27;;\n",
       "    }\n",
       "    return svg;\n",
       "}\n",
       "\n",
       "// Update images when the list is updated.\n",
       "listObj.on(&quot;updated&quot;, function (list) {\n",
       "    var query = $(&#x27;#mols2grid .m2g-searchbar&#x27;).val();\n",
       "    var template_mol;\n",
       "    if (query === &quot;&quot;) {\n",
       "        smarts_matches = {};\n",
       "        template_mol = null;\n",
       "    } else {\n",
       "        template_mol = RDKit.get_qmol(query);\n",
       "        template_mol.set_new_coords(true);\n",
       "    }\n",
       "    $(&#x27;#mols2grid .m2g-cell&#x27;).each(function() {\n",
       "        var $t = $(this);\n",
       "        var smiles = $t.children(&quot;.data-SMILES&quot;).first().text();\n",
       "        var index = parseInt(this.getAttribute(&quot;data-mols2grid-id&quot;));\n",
       "        var svg = draw_mol(smiles, index, template_mol);\n",
       "        $t.children(&quot;.data-img&quot;).html(svg);\n",
       "    });\n",
       "    if (template_mol) {\n",
       "        template_mol.delete();\n",
       "    }\n",
       "});\n",
       "    \n",
       "\n",
       "    // Trigger update to activate tooltips, draw images, setup callbacks...\n",
       "    listObj.update();\n",
       "    \n",
       "    // Set iframe height to fit content.\n",
       "    fitIframe(window.frameElement);\n",
       "});\n",
       "        &lt;/script&gt;\n",
       "\n",
       "\n",
       "\n",
       "\n",
       "    &lt;/body&gt;\n",
       "&lt;/html&gt;\n",
       "\">\n",
       "</iframe>"
      ],
      "text/plain": [
       "<IPython.core.display.HTML object>"
      ]
     },
     "execution_count": 10,
     "metadata": {},
     "output_type": "execute_result"
    }
   ],
   "source": [
    "mols2grid.display(acid_df,subset=[\"img\",\"Name\"])"
   ]
  },
  {
   "cell_type": "markdown",
   "id": "2d009b91",
   "metadata": {},
   "source": [
    "View the amines. "
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 11,
   "id": "0ffc3aaf",
   "metadata": {},
   "outputs": [
    {
     "data": {
      "application/vnd.jupyter.widget-view+json": {
       "model_id": "2a75231becf34f95bd4592f41fa3b941",
       "version_major": 2,
       "version_minor": 0
      },
      "text/plain": [
       "MolGridWidget()"
      ]
     },
     "metadata": {},
     "output_type": "display_data"
    },
    {
     "data": {
      "text/html": [
       "<style>\n",
       "    /* Some CSS to integrate with Jupyter more cleanly */\n",
       "    div.output_subarea {\n",
       "        /* Undo an unfortunate max-width parameter\n",
       "        that causes the output area to be too narrow\n",
       "        on smaller screens. */\n",
       "        max-width: none;\n",
       "\n",
       "        /* Align the table with the content */\n",
       "        padding: 0;\n",
       "\n",
       "        /* Let it breathe */\n",
       "        margin-top: 20px;\n",
       "    }\n",
       "</style>\n",
       "\n",
       "<iframe class=\"mols2grid-iframe\" frameborder=\"0\" width=\"100%\"\n",
       "    \n",
       "    \n",
       "    allow=\"clipboard-write\"\n",
       "    \n",
       "    \n",
       "    sandbox=\"allow-scripts allow-same-origin allow-downloads allow-popups allow-modals\"\n",
       "    \n",
       "    srcdoc=\"\n",
       "\n",
       "\n",
       "\n",
       "&lt;html lang=&quot;en&quot;&gt;\n",
       "    &lt;head&gt;\n",
       "        &lt;meta charset=&quot;UTF-8&quot; /&gt;\n",
       "        &lt;meta http-equiv=&quot;X-UA-Compatible&quot; content=&quot;IE=edge&quot; /&gt;\n",
       "        &lt;meta name=&quot;viewport&quot; content=&quot;width=device-width, initial-scale=1.0&quot; /&gt;\n",
       "        &lt;title&gt;Document!&lt;/title&gt;\n",
       "\n",
       "\n",
       "\n",
       "        &lt;style&gt;\n",
       "            /**\n",
       " * General styling\n",
       " */\n",
       "body {\n",
       "    font-family: &#x27;DejaVu&#x27;, sans-serif;\n",
       "}\n",
       "h1,h2,h3,h4 {\n",
       "    margin: 0 0 10px 0;\n",
       "}\n",
       "h1 {\n",
       "    font-size: 26px;\n",
       "}\n",
       "h2 {\n",
       "    font-size: 20px;\n",
       "    font-weight: 400;\n",
       "}\n",
       "h3 {\n",
       "\tfont-size: 16px;\n",
       "}\n",
       "p {\n",
       "    margin: 0 0 10px 0;\n",
       "}\n",
       "\n",
       "\n",
       "/* Remove body margin inside iframe */\n",
       "body.m2g-inside-iframe {\n",
       "    margin: 0;\n",
       "}\n",
       "\n",
       "/* In-cell text */\n",
       "#mols2grid .data:not(.data-img) {\n",
       "    height: 16px;\n",
       "    line-height: 16px;\n",
       "}\n",
       "/* Text truncation */\n",
       "#mols2grid .data {\n",
       "    /* Break text into multiple lines (default for static)... */\n",
       "    word-wrap: normal;\n",
       "\n",
       "    /* ...or truncate it (default for interactive). */\n",
       "    overflow: hidden;\n",
       "    white-space: nowrap;\n",
       "    text-overflow: ellipsis;\n",
       "}\n",
       "\n",
       "\n",
       "/**\n",
       " * Popover\n",
       " * - - -\n",
       " * Note: this is a bootstrap variable which is not namespaced.\n",
       " * To avoid any contamination, we only style it when the\n",
       " * x-placement parameter is set.\n",
       " */\n",
       ".popover[x-placement] {\n",
       "    font-family: &#x27;DejaVu&#x27;, sans-serif;\n",
       "    background: white;\n",
       "    border: solid 1px rgba(0,0,0,.2);\n",
       "    font-size: 12px;\n",
       "    padding: 10px;\n",
       "    border-radius: 5px;\n",
       "    box-shadow: 0 0 20px rgba(0,0,0,.15);\n",
       "    user-select: none;\n",
       "}\n",
       ".popover[x-placement] h3 {\n",
       "    margin: 0;\n",
       "}\n",
       ".popover[x-placement] .arrow {\n",
       "    width: 10px;\n",
       "    height: 10px;\n",
       "    background: #fff;\n",
       "    border: solid 1px rgba(0,0,0,.2);\n",
       "    box-sizing: border-box;\n",
       "    position: absolute;\n",
       "    transform-origin: 5px 5px;\n",
       "    clip-path: polygon(0 0, 100% 0, 100% 100%);\n",
       "}\n",
       ".popover[x-placement=&#x27;left&#x27;] .arrow {\n",
       "    transform: rotate(45deg);\n",
       "    top: 50%;\n",
       "    right: -5px;\n",
       "}\n",
       ".popover[x-placement=&#x27;right&#x27;] .arrow {\n",
       "    transform: rotate(-135deg);\n",
       "    top: 50%;\n",
       "    left: -5px;\n",
       "}\n",
       ".popover[x-placement=&#x27;top&#x27;] .arrow {\n",
       "    transform: rotate(135deg);\n",
       "    left: 50%;\n",
       "    bottom: -5px;\n",
       "}\n",
       ".popover[x-placement=&#x27;bottom&#x27;] .arrow {\n",
       "    transform: rotate(-45deg);\n",
       "    left: 50%;\n",
       "    top: -5px;\n",
       "}\n",
       "            body {\n",
       "    /* Colors */\n",
       "    --m2g-black: rgba(0,0,0,.75);\n",
       "    --m2g-black-soft: rgba(0,0,0,.35);\n",
       "    --m2g-black-10: rgba(0,0,0,.1);\n",
       "    --m2g-bg: #f6f6f6;\n",
       "    --m2g-border: solid 1px rgba(0,0,0,0.2);\n",
       "    --m2g-hl: #555; /* Highlight color */\n",
       "    --m2g-hl-shadow: inset 0 0 0 1px var(--m2g-hl); /* Inset 1px shadow to make border thicker */\n",
       "    --m2g-blue: #0f62fe;\n",
       "    --m2g-blue-soft: rgba(15,98,254,.2);\n",
       "\n",
       "    /* Icons */\n",
       "    --m2g-icn-triangle: url(&#x27;data:image/svg+xml;utf8,&lt;svg width=&quot;20&quot; fill=&quot;rgba(0,0,0,.75)&quot; height=&quot;20&quot; viewBox=&quot;0 0 20 20&quot; xmlns=&quot;http://www.w3.org/2000/svg&quot;&gt;&lt;path d=&quot;M9.5713 13.285L6.2543 7.757C6.0543 7.424 6.2953 7 6.6823 7L13.3173 7C13.7053 7 13.9463 7.424 13.7453 7.757L10.4283 13.285C10.2343 13.609 9.7653 13.609 9.5713 13.285Z&quot;/&gt;&lt;/svg&gt;&#x27;);\n",
       "    --m2g-icn-triangle-white: url(&#x27;data:image/svg+xml;utf8,&lt;svg width=&quot;20&quot; fill=&quot;white&quot; height=&quot;20&quot; viewBox=&quot;0 0 20 20&quot; xmlns=&quot;http://www.w3.org/2000/svg&quot;&gt;&lt;path d=&quot;M9.5713 13.285L6.2543 7.757C6.0543 7.424 6.2953 7 6.6823 7L13.3173 7C13.7053 7 13.9463 7.424 13.7453 7.757L10.4283 13.285C10.2343 13.609 9.7653 13.609 9.5713 13.285Z&quot;/&gt;&lt;/svg&gt;&#x27;);\n",
       "    --m2g-icn-cb-white: url(&#x27;data:image/svg+xml;utf8,&lt;svg width=&quot;16&quot; height=&quot;16&quot; viewBox=&quot;0 0 16 16&quot; fill=&quot;none&quot; stroke=&quot;white&quot; stroke-width=&quot;2.5&quot; stroke-linecap=&quot;round&quot; xmlns=&quot;http://www.w3.org/2000/svg&quot;&gt;&lt;path d=&quot;M4 7.65686L7 10.6569L12.6569 5.00001&quot;/&gt;&lt;/svg&gt;&#x27;);\n",
       "    \n",
       "    /* Border radius */\n",
       "    --m2g-br: 3px;\n",
       "    --m2g-br-l: var(--m2g-br) 0 0 var(--m2g-br); /* Left-only */\n",
       "    --m2g-br-r: 0 var(--m2g-br) var(--m2g-br) 0; /* Right-only */\n",
       "\n",
       "    /* Text */\n",
       "    --m2g-fs: 14px; /* UI font-size */\n",
       "    --m2g-fs-cell: 12px; /* Cell font-size */\n",
       "\n",
       "    /* Transition speeds */\n",
       "    --m2g-trans: 150ms;\n",
       "\n",
       "    /* Layout */\n",
       "    --m2g-h: 40px; /* Form element height */\n",
       "}\n",
       "\n",
       "/* Styling */\n",
       "#mols2grid {\n",
       "    font-family: &#x27;DejaVu&#x27;, sans-serif;\n",
       "    font-size: var(--m2g-fs);\n",
       "}\n",
       "\n",
       "/* Fixes */\n",
       "#mols2grid *,\n",
       "#mols2grid *::before,\n",
       "#mols2grid *::after {\n",
       "    box-sizing: border-box;\n",
       "    outline: none;\n",
       "}\n",
       "\n",
       "\n",
       "\n",
       "/**\n",
       " * Functions section\n",
       " */\n",
       "\n",
       "#mols2grid .m2g-functions {\n",
       "    display: flex;\n",
       "}\n",
       "#mols2grid .m2g-functions .m2g-row {\n",
       "    flex: 0;\n",
       "    display: flex;\n",
       "}\n",
       "\n",
       "/* Individual elements don&#x27;t scale */\n",
       "#mols2grid .m2g-functions .m2g-row &gt; * {\n",
       "    flex: 0 0;\n",
       "    margin-right: 10px;\n",
       "}\n",
       "#mols2grid .m2g-functions .m2g-row:last-child &gt; *:last-child {\n",
       "    margin-right: 0;\n",
       "}\n",
       "\n",
       "/* Row 1: pagination + gap + sort */\n",
       "#mols2grid .m2g-functions .m2g-row:first-child {\n",
       "    flex: 1; /* Scale */\n",
       "}\n",
       "#mols2grid .m2g-functions .m2g-gap {\n",
       "    /* The gap in between will scale, so the pagination\n",
       "    stays on the left, while the rest moves to the right */\n",
       "    flex: 1;\n",
       "    margin-right: 0;\n",
       "}\n",
       "\n",
       "\n",
       "\n",
       "/*\n",
       " * Pagination\n",
       " */\n",
       "\n",
       "#mols2grid ul.m2g-pagination {\n",
       "    /* Unset defaults */\n",
       "    list-style-type: none;\n",
       "    margin-block-start: 0;\n",
       "    margin-block-end: 0;\n",
       "    margin-inline-start: 0;\n",
       "    margin-inline-end: 0;\n",
       "    padding-inline-start: 0;\n",
       "\n",
       "    /* Custom */\n",
       "    display: flex;\n",
       "}\n",
       "#mols2grid ul.m2g-pagination li {\n",
       "    background: var(--m2g-bg) ;\n",
       "    border: var(--m2g-border);\n",
       "    height: var(--m2g-h);\n",
       "    min-width: calc(var(--m2g-h) + 1px);\n",
       "    position: relative;\n",
       "    user-select: none;\n",
       "    \n",
       "    /* Compensate for double border */\n",
       "    margin-right: -1px;\n",
       "    \n",
       "    /* Center text */\n",
       "    display: flex;\n",
       "    align-items: center;\n",
       "    justify-content: center;\n",
       "}\n",
       "#mols2grid ul.m2g-pagination li:last-child {\n",
       "    min-width: var(--m2g-h);\n",
       "}\n",
       "#mols2grid ul.m2g-pagination li a {\n",
       "    text-decoration: none;\n",
       "    color: var(--m2g-black);\n",
       "    padding: 0 10px;\n",
       "    width: 100%;\n",
       "    height: var(--m2g-h);\n",
       "    line-height: var(--m2g-h);\n",
       "    text-align: center;\n",
       "    /* Compensate for border so there&#x27;s no gap between click areas  */\n",
       "    margin: 0 -1px;\n",
       "}\n",
       "\n",
       "/* Corner shape */\n",
       "#mols2grid ul.m2g-pagination li:first-child {\n",
       "    border-radius: var(--m2g-br-l);\n",
       "}\n",
       "#mols2grid ul.m2g-pagination li:last-child {\n",
       "    border-radius: var(--m2g-br-r);\n",
       "    margin-right: 0;\n",
       "}\n",
       "\n",
       "/* Focus state */\n",
       "#mols2grid ul.m2g-pagination li:focus-within {\n",
       "    border-color: var(--m2g-hl);\n",
       "    box-shadow: var(--m2g-hl-shadow);\n",
       "    z-index: 1;\n",
       "}\n",
       "\n",
       "/* Active state */\n",
       "#mols2grid ul.m2g-pagination li.active {\n",
       "    background: var(--m2g-hl);\n",
       "    z-index: 1;\n",
       "}\n",
       "#mols2grid ul.m2g-pagination li.active a {\n",
       "    cursor: default;\n",
       "    color: #fff;\n",
       "}\n",
       "\n",
       "/* Disabled sate */\n",
       "#mols2grid ul.m2g-pagination li.disabled a {\n",
       "    cursor: default;\n",
       "    color: rgba(0,0,0,.25);\n",
       "    pointer-events: none;\n",
       "}\n",
       "\n",
       "\n",
       "\n",
       "/*\n",
       " * Dropdowns\n",
       " */\n",
       "\n",
       "#mols2grid ::placeholder {\n",
       "    color: var(--m2g-black-soft);\n",
       "}\n",
       "#mols2grid .m2g-dropdown {\n",
       "    height: var(--m2g-h);\n",
       "    background: var(--m2g-bg);\n",
       "    border: var(--m2g-border);\n",
       "    border-radius: var(--m2g-br);\n",
       "    position: relative;\n",
       "}\n",
       "#mols2grid .m2g-dropdown select {\n",
       "    -webkit-appearance: none;\n",
       "    -moz-appearance: none;\n",
       "    -ms-appearance: none;\n",
       "    appearance: none;\n",
       "    background: transparent;\n",
       "    border: none;\n",
       "    height: 100%;\n",
       "    padding: 0 13px;\n",
       "    min-width: 0;\n",
       "    max-width: 250px;\n",
       "    color: var(--m2g-black);\n",
       "    cursor: pointer;\n",
       "}\n",
       "\n",
       "/* Icon */\n",
       "#mols2grid .m2g-dropdown .m2g-icon {\n",
       "    width: 30px;\n",
       "    height: var(--m2g-h);\n",
       "    display: flex;\n",
       "    align-items: center;\n",
       "    justify-content: center;\n",
       "    position: absolute;\n",
       "    top: 0;\n",
       "    right: 0;\n",
       "    pointer-events: none;\n",
       "}\n",
       "#mols2grid .m2g-dropdown .m2g-icon svg:not(.m2g-stroke) {\n",
       "    fill: var(--m2g-black);\n",
       "}\n",
       "#mols2grid .m2g-dropdown .m2g-icon svg.m2g-stroke {\n",
       "    stroke: var(--m2g-black);\n",
       "}\n",
       "\n",
       "/* Display */\n",
       "/* We hide the native select element because\n",
       " * it is limited in styling. Instead, we display\n",
       " * the selected value in a div. */\n",
       "#mols2grid .m2g-dropdown .m2g-display {\n",
       "    position: absolute;\n",
       "    left: 0;\n",
       "    right: 0;\n",
       "    top: 0;\n",
       "    bottom: 0;\n",
       "    pointer-events: none;\n",
       "    color: var(--m2g-black);\n",
       "    line-height: var(--m2g-h);\n",
       "    padding: 0 25px 0 13px;\n",
       "\n",
       "    /* Truncate dropdown text */\n",
       "    white-space: nowrap;\n",
       "\ttext-overflow: ellipsis;\n",
       "\toverflow: hidden;\n",
       "}\n",
       "\n",
       "/* Focus state */\n",
       "#mols2grid .m2g-dropdown:focus-within {\n",
       "    border-color: var(--m2g-hl);\n",
       "    box-shadow: var(--m2g-hl-shadow);\n",
       "}\n",
       "\n",
       "\n",
       "\n",
       "/**\n",
       " * Action dropdown\n",
       " */\n",
       "\n",
       "#mols2grid .m2g-dropdown.m2g-actions {\n",
       "    width: var(--m2g-h);\n",
       "    padding: 0;\n",
       "}\n",
       "#mols2grid .m2g-dropdown.m2g-actions select {\n",
       "    opacity: 0;\n",
       "    width: var(--m2g-h);\n",
       "}\n",
       "#mols2grid .m2g-dropdown.m2g-actions .m2g-icon {\n",
       "    width: var(--m2g-h);\n",
       "}\n",
       "\n",
       "\n",
       "\n",
       "/*\n",
       " * Sort dropdown\n",
       " */\n",
       "\n",
       "#mols2grid .m2g-dropdown.m2g-sort {\n",
       "    flex: 0 0 200px;\n",
       "    width: 200px; /* Needed in addition to flex-basis for small sizes! */\n",
       "    border-radius: var(--m2g-br);\n",
       "    background: var(--m2g-bg);\n",
       "    display: flex;\n",
       "}\n",
       "\n",
       "/* Dropdown */\n",
       "#mols2grid .m2g-dropdown.m2g-sort select {\n",
       "    flex: 1 1;\n",
       "    opacity: 0;\n",
       "    /* padding-right: 70px; Space for &quot;Sort:&quot; */\n",
       "    box-sizing: border-box;\n",
       "}\n",
       "\n",
       "/* Sort order */\n",
       "#mols2grid .m2g-dropdown.m2g-sort .m2g-order {\n",
       "    background: var(--m2g-bg) var(--m2g-icn-triangle) no-repeat center;\n",
       "    flex: 0 0 30px;\n",
       "    height: 100%;\n",
       "    border-left: var(--m2g-border);\n",
       "    cursor: pointer;\n",
       "}\n",
       "#mols2grid .m2g-dropdown.m2g-sort.m2d-arrow-desc .m2g-order {\n",
       "    transform: rotate(180deg);\n",
       "    border-left: none;\n",
       "    border-right: var(--m2g-border);\n",
       "}\n",
       "\n",
       "/* Display */\n",
       "#mols2grid .m2g-dropdown.m2g-sort .m2g-display {\n",
       "    right: 31px;\n",
       "    padding-right: 13px;\n",
       "}\n",
       "#mols2grid .m2g-dropdown.m2g-sort .m2g-display::before {\n",
       "    content: &#x27;Sort: &#x27;;\n",
       "}\n",
       "\n",
       "/* Focus state */\n",
       "#mols2grid .m2g-dropdown.m2g-sort:focus-within .m2g-display,\n",
       "#mols2grid .m2g-dropdown.m2g-sort:focus-within .m2g-order {\n",
       "    background-color: transparent;\n",
       "}\n",
       "\n",
       "\n",
       "\n",
       "/*\n",
       " * Search bar\n",
       " */\n",
       "\n",
       "#mols2grid .m2g-search-wrap {\n",
       "    height: var(--m2g-h);\n",
       "    display: flex;\n",
       "    align-items: center;\n",
       "    justify-content: flex-end;\n",
       "    background: var(--m2g-bg);\n",
       "    border: var(--m2g-border);\n",
       "    border-radius: var(--m2g-br);\n",
       "}\n",
       "#mols2grid .m2g-searchbar {\n",
       "    width: 170px;\n",
       "    height: var(--m2g-h);\n",
       "    padding: 0 13px;\n",
       "    border: none;\n",
       "    color: var(--m2g-black);\n",
       "    cursor: text;\n",
       "    background: transparent;\n",
       "}\n",
       "\n",
       "/* Focus state */\n",
       "#mols2grid .m2g-search-wrap:focus-within {\n",
       "    border-color: var(--m2g-hl);\n",
       "    box-shadow: var(--m2g-hl-shadow);\n",
       "}\n",
       "\n",
       "/* Option buttons */\n",
       "#mols2grid .m2g-search-options {\n",
       "    font-size: 12px;\n",
       "    display: flex;\n",
       "    height: calc(1.5em + .75rem);\n",
       "    line-height: calc(1.5em + .75rem);\n",
       "    margin-right: 5px;\n",
       "    border-radius: var(--m2g-br);\n",
       "    color: var(--m2g-black);\n",
       "}\n",
       "#mols2grid .m2g-search-options .m2g-option {\n",
       "    background: var(--m2g-black-10);\n",
       "    padding: 0 13px;\n",
       "    cursor: default;\n",
       "    user-select: none;\n",
       "}\n",
       "#mols2grid .m2g-search-options .m2g-option:not(.sel) {\n",
       "    cursor: pointer;\n",
       "}\n",
       "#mols2grid .m2g-search-options .m2g-option:first-child {\n",
       "    border-radius: 2px 0 0 2px;\n",
       "}\n",
       "#mols2grid .m2g-search-options .m2g-option:last-child {\n",
       "    border-radius: 0 2px 2px 0;\n",
       "}\n",
       "#mols2grid .m2g-search-options .m2g-option.sel {\n",
       "    background: var(--m2g-hl);\n",
       "    color: #fff;\n",
       "}\n",
       "\n",
       "\n",
       "\n",
       "/**\n",
       " * Grid\n",
       " */\n",
       "\n",
       "/* Container */\n",
       "#mols2grid .m2g-list {\n",
       "    display: flex;\n",
       "    flex-wrap: wrap;\n",
       "    align-items: flex-start;\n",
       "    justify-content: flex-start;\n",
       "    padding: 1px; /* Compensate for negative padding on cell */\n",
       "    user-select: none;\n",
       "    margin: 0px;\n",
       "    margin-top: 20px;\n",
       "    font-family: &#x27;DejaVu&#x27;, sans-serif;\n",
       "    \n",
       "}\n",
       "\n",
       "/* Cell */\n",
       "#mols2grid .m2g-cell {\n",
       "    border: 1px solid #cccccc;\n",
       "    text-align: center;\n",
       "    vertical-align: top;\n",
       "    font-family: var(--font-family);\n",
       "    padding: 10px;\n",
       "    padding-top: max(10px, 20px);\n",
       "    margin: -1px -1px 0 0;\n",
       "    flex: 1 0 130px;\n",
       "    position: relative;\n",
       "    font-size: var(--m2g-fs-cell);\n",
       "    cursor: pointer;\n",
       "    color: var(--m2g-black);\n",
       "    overflow: hidden;\n",
       "    box-sizing: border-box;\n",
       "    background-color: white;\n",
       "}\n",
       "#mols2grid .m2g-cell:focus {\n",
       "    z-index: 1;\n",
       "    border-color: var(--m2g-hl);\n",
       "    box-shadow: var(--m2g-hl-shadow);\n",
       "}\n",
       "\n",
       "/* Phantom cells to maintain grid structure with less results */\n",
       "#mols2grid .m2g-cell.m2g-phantom {\n",
       "    border: none;\n",
       "    pointer-events: none;\n",
       "    height: 0;\n",
       "    padding: 0;\n",
       "}\n",
       "\n",
       "/* Checkbox &amp; ID */\n",
       "#mols2grid .m2g-cb-wrap {\n",
       "    position: absolute;\n",
       "    top: 3px;\n",
       "    left: 3px;\n",
       "    display: flex;\n",
       "    border-radius: 2px;\n",
       "    font-size: 0;\n",
       "    line-height: 0;\n",
       "    padding: 3px;\n",
       "    padding-right: 0;\n",
       "}\n",
       "#mols2grid .m2g-cb-wrap input[type=checkbox] {\n",
       "    display: none;\n",
       "}\n",
       "#mols2grid .m2g-cb-wrap input[type=checkbox] + .m2g-cb {\n",
       "\twidth: 16px;\n",
       "\theight: 16px;\n",
       "\tbox-sizing: border-box;\n",
       "\tbackground: #fff;\n",
       "\tborder: var(--m2g-border);\n",
       "\tborder-radius: 2px;\n",
       "    margin-right: 5px;\n",
       "}\n",
       "#mols2grid .m2g-cb-wrap input[type=checkbox]:checked + .m2g-cb {\n",
       "    border: none;\n",
       "    background-color: var(--m2g-blue);\n",
       "    background-image: var(--m2g-icn-cb-white);\n",
       "}\n",
       "#mols2grid .m2g-tooltip {\n",
       "    /* This is a div spanning full cell size where the\n",
       "    tooltip is rendered around, because you can&#x27;t attach\n",
       "    it to the parent due to list.js limitation. */\n",
       "    width: 100%;\n",
       "    height: 100%;\n",
       "    position: absolute;\n",
       "    left: 0;\n",
       "    top: 0;\n",
       "    z-index: -1;\n",
       "    pointer-events: none;\n",
       "    opacity: 0;\n",
       "}\n",
       "#mols2grid .m2g-cell:has(:checked) {\n",
       "    background: #ffd !important; /* Overrides user-set background color */\n",
       "}\n",
       "#mols2grid .data-mols2grid-id-display {\n",
       "    font-size: var(--m2g-fs-cell);\n",
       "    line-height: 16px;\n",
       "}\n",
       "#mols2grid .m2g-cb-wrap input[type=checkbox] + .data-mols2grid-id-display {\n",
       "    padding: 0 5px 0 5px;\n",
       "}\n",
       "#mols2grid .m2g-cb-wrap .data-name-display {\n",
       "    font-size: var(--m2g-fs);\n",
       "    line-height: 16px;\n",
       "}\n",
       "\n",
       "/* Info + callback button wrap (28px high) */\n",
       "#mols2grid .m2g-cell-actions {\n",
       "    position: absolute;\n",
       "    top: 0;\n",
       "    right: 0;\n",
       "    display: flex;\n",
       "    flex-direction: row;\n",
       "    font-size: 0;\n",
       "    line-height: 0;\n",
       "    \n",
       "    /* background: yellow; */\n",
       "}\n",
       "\n",
       "/* Info button */\n",
       "#mols2grid .m2g-info {\n",
       "    width: 28px;\n",
       "    height: 28px;\n",
       "    border-radius: 2px;\n",
       "    line-height: 28px;\n",
       "    font-size: min(14px, 12px);\n",
       "    font-family: Georgia, serif;\n",
       "    font-style: italic;\n",
       "    padding: 0;\n",
       "    text-align: center;\n",
       "}\n",
       "#mols2grid .m2g-keep-tooltip .m2g-info {\n",
       "    color: #fff;\n",
       "}\n",
       "#mols2grid .m2g-keep-tooltip .m2g-info::before {\n",
       "    content: &#x27;i&#x27;;\n",
       "    width: 18px;\n",
       "    height: 18px;\n",
       "    line-height: 18px;\n",
       "    background: var(--m2g-hl);\n",
       "    position: absolute;\n",
       "    left: 5px;\n",
       "    top: 5px;\n",
       "    border-radius: 9px;\n",
       "}\n",
       "\n",
       "/* Callback button */\n",
       "#mols2grid .m2g-callback {\n",
       "    width: 28px;\n",
       "    height: 28px;\n",
       "    cursor: pointer;\n",
       "}\n",
       "#mols2grid .m2g-callback::after {\n",
       "    content: &#x27;&#x27;;\n",
       "    display: block;\n",
       "    width: 16px;\n",
       "    height: 16px;\n",
       "    margin: 6px;\n",
       "    border: var(--m2g-border);\n",
       "    border-radius: 2px;\n",
       "    background: var(--m2g-bg) var(--m2g-icn-triangle) no-repeat center;\n",
       "    transform: rotate(-90deg);\n",
       "}\n",
       "\n",
       "/* Image */\n",
       "#mols2grid .m2g-cell .data-img {\n",
       "    padding: 0;\n",
       "}\n",
       "#mols2grid .m2g-cell img,\n",
       "#mols2grid .m2g-cell svg {\n",
       "    max-width: 100%;\n",
       "    height: auto;\n",
       "    padding: 0;\n",
       "}\n",
       "#mols2grid .m2g-cell svg &gt; rect:first-child {\n",
       "    /* Remove the SVG background */\n",
       "    fill: transparent !important;\n",
       "}\n",
       "\n",
       "/* Text below image */\n",
       ".m2g-copy-blink {\n",
       "    animation: m2g-blink var(--m2g-trans) 3;\n",
       "}\n",
       "@keyframes m2g-blink {\n",
       "    0% {\n",
       "        opacity: 1;\n",
       "    }\n",
       "    49% {\n",
       "        opacity: 1;\n",
       "    }\n",
       "    50% {\n",
       "        opacity: 0;\n",
       "    }\n",
       "    100% {\n",
       "        opacity: 0;\n",
       "    }\n",
       "}\n",
       "\n",
       "/* Copyable text */\n",
       ".copy-me {\n",
       "    position: relative;\n",
       "    cursor: pointer;\n",
       "}\n",
       "\n",
       "\n",
       "\n",
       "/**\n",
       " * Modal popup\n",
       " * - - -\n",
       " * Triggered by make_popup_callback()\n",
       " * See https://mols2grid.readthedocs.io/en/latest/notebooks/callbacks.html#Display-a-popup-containing-descriptors\n",
       " */\n",
       "\n",
       "/* Container */\n",
       "#m2g-modal-container {\n",
       "    display: flex;\n",
       "    align-items: center;\n",
       "    justify-content: center;\n",
       "    background: var(--m2g-black-10);\n",
       "    position: fixed;\n",
       "    top: 0;\n",
       "    left: 0;\n",
       "    z-index: 1;\n",
       "    width: 100%;\n",
       "    height: 100%;\n",
       "    \n",
       "    /* Transition */\n",
       "    opacity: 0;\n",
       "    transition: opacity var(--m2g-trans) linear;\n",
       "}\n",
       "\n",
       "/* Modal */\n",
       "#m2g-modal {\n",
       "    background: #fff;\n",
       "    border-radius: var(--m2g-br);\n",
       "    box-shadow: 0 0 30px var(--m2g-black-10);\n",
       "    padding: 20px;\n",
       "    position: relative;\n",
       "    max-width: calc(100% - 80px);\n",
       "    max-height: calc(100% - 80px);\n",
       "    display: flex;\n",
       "    flex-direction: column;\n",
       "    min-width: 26px;\n",
       "\n",
       "    /* Transition */\n",
       "    opacity: 0;\n",
       "    transform: translate(0, 5px);\n",
       "    transition: transform var(--m2g-trans) ease-in-out, opacity var(--m2g-trans) linear;\n",
       "}\n",
       "#m2g-modal .m2g-modal-header {\n",
       "    flex: 0 0 26px;\n",
       "    margin-bottom: 10px;\n",
       "}\n",
       "#m2g-modal .m2g-modal-header h2 {\n",
       "    margin-bottom: 0;\n",
       "}\n",
       "#m2g-modal .m2g-modal-header h2 + p {\n",
       "    font-size: 15px;\n",
       "}\n",
       "#m2g-modal .m2g-modal-body {\n",
       "    flex: 1;\n",
       "    position: relative;\n",
       "}\n",
       "\n",
       "/* Transition */\n",
       "#m2g-modal-container.show {\n",
       "    opacity: 1;\n",
       "}\n",
       "#m2g-modal-container.show #m2g-modal {\n",
       "    opacity: 1;\n",
       "    transform: translate(0, 0);\n",
       "}\n",
       "\n",
       "/* Header + close btn */\n",
       "#m2g-modal h2 {\n",
       "    line-height: 26px;\n",
       "    padding-right: 40px;\n",
       "    text-transform: capitalize;\n",
       "}\n",
       "#m2g-modal h3 {\n",
       "    \n",
       "}\n",
       "#m2g-modal button.close {\n",
       "    background: transparent;\n",
       "    padding: 0;\n",
       "    color: var(--m2g-black);\n",
       "    font-size: 1.5rem;\n",
       "    width: 40px;\n",
       "    height: 40px;\n",
       "    position: absolute;\n",
       "    top: 13px;\n",
       "    right: 13px;\n",
       "    border: none;\n",
       "}\n",
       "\n",
       "/* Image */\n",
       "#m2g-modal .svg-wrap svg {\n",
       "    max-width: 100%;\n",
       "    margin-bottom: 20px;\n",
       "}\n",
       "\n",
       "/* Separator */\n",
       "hr {\n",
       "    width: 100%;\n",
       "    height: 1px;\n",
       "    background: #ddd;\n",
       "    margin: 15px 0;\n",
       "    border: none;\n",
       "}\n",
       "\n",
       "\n",
       "\n",
       "/**\n",
       " * Hover states\n",
       " */\n",
       "@media (hover:hover) {\n",
       "    /* Pagination */\n",
       "    #mols2grid ul.m2g-pagination li:not(.active):not(.disabled):hover {\n",
       "        background: #f0f0f0;\n",
       "        z-index: 1;\n",
       "    }\n",
       "    #mols2grid ul.m2g-pagination li.active + li:hover {\n",
       "        /* Keeping the hover border consiistent */\n",
       "        margin-left: 1px;\n",
       "        border-left: none;\n",
       "        min-width: 40px;\n",
       "    }\n",
       "\n",
       "    /* Dropdowns &amp; search */\n",
       "    #mols2grid .m2g-dropdown:not(:focus-within):hover,\n",
       "    #mols2grid .m2g-search-wrap:not(:focus-within):hover,\n",
       "    #mols2grid .m2g-sort:not(:focus-within) .m2g-order:hover {\n",
       "        background-color: #f0f0f0;\n",
       "    }\n",
       "    #mols2grid .m2g-search-wrap:not(:focus-within):hover {\n",
       "        background: #fff;\n",
       "        border-color: rgba(0,0,0,.3);\n",
       "    }\n",
       "    /* Hocus pocus to have separate hover states for dropdown and arrow */\n",
       "    #mols2grid .m2g-dropdown.m2g-sort:not(:focus-within):hover .m2g-order:not(:hover) + .m2g-display {\n",
       "        background-color: transparent;\n",
       "    }\n",
       "\n",
       "    /* Search options */\n",
       "    #mols2grid .m2g-search-options .m2g-option:not(.sel):hover {\n",
       "        background: rgba(0,0,0,.15);\n",
       "    }\n",
       "\n",
       "    /* Grid */\n",
       "    /* Note: this is in an ::after pseudo element, so the transparent\n",
       "    hover color plays nice with the cell background color. */\n",
       "    #mols2grid .m2g-cell:hover::after {\n",
       "        content: &#x27;&#x27;;\n",
       "        width: 100%;\n",
       "        height: 100%;\n",
       "        position: absolute;\n",
       "        top: 0;\n",
       "        left: 0;\n",
       "        background-color: rgba(0,0,0,0.05);\n",
       "        pointer-events: none;\n",
       "    }\n",
       "\n",
       "    /* info button */\n",
       "    #mols2grid .m2g-info:hover::before {\n",
       "        content: &#x27;i&#x27;;\n",
       "        color: #fff;\n",
       "        width: 18px;\n",
       "        height: 18px;\n",
       "        line-height: 18px;\n",
       "        background: var(--m2g-hl);\n",
       "        position: absolute;\n",
       "        left: 5px;\n",
       "        top: 5px;\n",
       "        border-radius: 9px;\n",
       "    }\n",
       "    \n",
       "    /* Callback button */\n",
       "    #mols2grid .m2g-callback:hover::after {\n",
       "        background-color: var(--m2g-black);\n",
       "        background-image: var(--m2g-icn-triangle-white);\n",
       "        border-color: transparent;\n",
       "    }\n",
       "\n",
       "    /* Copyable text */\n",
       "    .copy-me:hover {\n",
       "        text-decoration: underline;\n",
       "        text-decoration-color: var(--m2g-blue);\n",
       "    }\n",
       "}\n",
       "\n",
       "\n",
       "\n",
       "/**\n",
       " * Responsive behavior.\n",
       " * - - -\n",
       " * Note: container queries won&#x27;t work in older browsers,\n",
       " * but this is purely aesthetical behavior so that&#x27;s ok.\n",
       " * https://caniuse.com/css-container-queries\n",
       " */\n",
       "\n",
       "/* This sets the msg-list div as reference container */\n",
       "#mols2grid {\n",
       "    container-type: inline-size;\n",
       "}\n",
       "\n",
       "\n",
       "\n",
       "/**\n",
       " * Functions section\n",
       " */\n",
       "\n",
       "/* When there&#x27;s not enough space to put everything in one row, we break it into two.\n",
       " * - - -\n",
       " * 870px = pagination 280 + sort 200 + search 300 + menu 40 + (3*10 gap) = 850 + 20 buffer.\n",
       " * Buffer required because the button width inside the search depends on the font.\n",
       " */\n",
       "@container (max-width: 870px) {\n",
       "    #mols2grid .m2g-functions {\n",
       "        flex-direction: column-reverse;\n",
       "        gap: 10px;\n",
       "    }\n",
       "    #mols2grid .m2g-functions .m2g-row:last-child {\n",
       "        justify-content: flex-end;\n",
       "    }\n",
       "    #mols2grid .m2g-functions .m2g-row:first-child *:last-child {\n",
       "        margin-right: 0;\n",
       "    }\n",
       "}\n",
       "\n",
       "/* When there&#x27;s not enough room for pagination + sort on one row,\n",
       " * we reduce the sort drodpwon width.\n",
       " */\n",
       "@container (max-width: 500px) {\n",
       "    #mols2grid .m2g-functions .m2g-sort {\n",
       "        width: 80px;\n",
       "        flex-basis: 80px;\n",
       "    }\n",
       "    #mols2grid .m2g-functions .m2g-sort .m2g-display {\n",
       "        font-size: 0;\n",
       "        line-height: 0;\n",
       "        padding-right: 0;\n",
       "    }\n",
       "    #mols2grid .m2g-functions .m2g-sort .m2g-display::before {\n",
       "        content: &#x27;Sort&#x27;;\n",
       "        font-size: var(--m2g-fs);\n",
       "        line-height: var(--m2g-h);\n",
       "    }\n",
       "}\n",
       "\n",
       "/* When there&#x27;s not enough room for pagination + reduced sort on one row,\n",
       " * we reduce the pagination width.\n",
       " */\n",
       "@container (max-width: 500px) {\n",
       "    /* We&#x27;re overriding min-width from different\n",
       "    locations, including responsive rules */\n",
       "    #mols2grid ul.m2g-pagination li,\n",
       "    #mols2grid ul.m2g-pagination li:last-child,\n",
       "    #mols2grid ul.m2g-pagination li.active + li:hover {\n",
       "        min-width: 0;\n",
       "    }\n",
       "}\n",
       "\n",
       "/* When there&#x27;s not enough room for searchbar + menu\n",
       " * we scale down the searchbar to fit the container.\n",
       " */\n",
       "@container (max-width: 370px) {\n",
       "    #mols2grid .m2g-functions .m2g-row .m2g-search-wrap {\n",
       "        flex: 1;\n",
       "    }\n",
       "    #mols2grid .m2g-searchbar {\n",
       "        width: calc(100% - 50px);\n",
       "    }\n",
       "    #mols2grid .m2g-search-options {\n",
       "        width: 50px;\n",
       "    }\n",
       "\n",
       "    /* Collapse options in T/M buttons */\n",
       "    #mols2grid .m2g-search-options .m2g-option {\n",
       "        width: 25px;\n",
       "        text-align: center;\n",
       "        padding: 0;\n",
       "        overflow: hidden;\n",
       "    }\n",
       "    #mols2grid .m2g-search-options .m2g-option:first-child::before {\n",
       "        content: &#x27;T\\A&#x27;\n",
       "    }\n",
       "    #mols2grid .m2g-search-options .m2g-option:last-child::before {\n",
       "        content: &#x27;S\\A&#x27;\n",
       "    }\n",
       "}\n",
       "\n",
       "\n",
       "\n",
       "/**\n",
       " * Grid\n",
       " */\n",
       "\n",
       "/* When there&#x27;s room for 5 columns, fall back to 4 */\n",
       "@container (min-width: 519px) and (max-width: 779px) {\n",
       "    #mols2grid .m2g-cell {\n",
       "        flex-basis: calc(100% / 4);\n",
       "    }\n",
       "}\n",
       "\n",
       "/* When there&#x27;s room for 7-11 columns, fall back to 6 */\n",
       "@container (min-width: 779px) and (max-width: 1559px) {\n",
       "    #mols2grid .m2g-cell {\n",
       "        flex-basis: calc(100% / 6);\n",
       "    }\n",
       "}\n",
       "\n",
       "/* When there&#x27;s room for 13+ columns, fall back to 12 */\n",
       "@container (min-width: 1559px) {\n",
       "    #mols2grid .m2g-cell {\n",
       "        flex-basis: calc(100% / 12);\n",
       "    }\n",
       "}\n",
       "\n",
       "            /* Custom CSS */\n",
       "            \n",
       "        &lt;/style&gt;\n",
       "        &lt;script src=&quot;https://cdnjs.cloudflare.com/ajax/libs/list.js/2.3.1/list.min.js&quot;&gt;&lt;/script&gt;\n",
       "&lt;script src=&quot;https://code.jquery.com/jquery-3.6.0.min.js&quot; integrity=&quot;sha256-/xUj+3OJU5yExlq6GSYGSHk7tPXikynS7ogEvDej/m4=&quot; crossorigin=&quot;anonymous&quot;&gt;&lt;/script&gt;\n",
       "&lt;script src=&quot;https://unpkg.com/@rdkit/rdkit@2022.3.1/Code/MinimalLib/dist/RDKit_minimal.js&quot;&gt;&lt;/script&gt;\n",
       "        &lt;script&gt;\n",
       "    // Set iframe height to fit content.\n",
       "    function fitIframe(iframe) {\n",
       "        // Ignore when there&#x27;s no iframe\n",
       "        if (!iframe) return\n",
       "\n",
       "        // Only fit height when no specific height was given.\n",
       "        if (iframe.getAttribute(&#x27;height&#x27;)) return;\n",
       "\n",
       "        // Initial fit + refit whenever the window width changes.\n",
       "        _fit()\n",
       "        $(window).on(&#x27;resize&#x27;, function() {\n",
       "            if (window.innerWidth != window.prevInnerWidth) {\n",
       "                window.prevInnerWidth = window.innerWidth\n",
       "                _fit();\n",
       "            }\n",
       "        })\n",
       "\n",
       "        // Fit iframe height to content height.\n",
       "        function _fit() {\n",
       "            var height = iframe.contentDocument.body.scrollHeight + 18 + &#x27;px&#x27;;\n",
       "            iframe.style.height = height;\n",
       "        }\n",
       "    }\n",
       "&lt;/script&gt;\n",
       "\n",
       "&lt;!-- prettier-ignore --&gt;\n",
       "&lt;script src=&quot;https://cdn.jsdelivr.net/npm/bootstrap@4.6.0/dist/js/bootstrap.bundle.min.js&quot; integrity=&quot;sha384-Piv4xVNRyMGpqkS2by6br4gNJ7DXjqk09RmUpJ8jgGtD7zP9yug3goQfGII0yAns&quot; crossorigin=&quot;anonymous&quot;&gt;&lt;/script&gt;\n",
       "        \n",
       "        &lt;!-- Custom header --&gt;\n",
       "        \n",
       "\n",
       "\n",
       "\n",
       "\n",
       "    &lt;/head&gt;\n",
       "    &lt;body class=&quot;m2g-inside-iframe&quot;&gt;\n",
       "\n",
       "\n",
       "\n",
       "        &lt;div id=&quot;mols2grid&quot; class=&quot;grid-default&quot;&gt;\n",
       "            &lt;!-- Pagination &amp; search --&gt;\n",
       "            &lt;div class=&quot;m2g-functions&quot;&gt;\n",
       "                \n",
       "                &lt;div class=&quot;m2g-row&quot;&gt;\n",
       "                    &lt;!-- Pagination --&gt;\n",
       "                    &lt;ul class=&quot;m2g-pagination&quot; class=&quot;d-flex&quot;&gt;&lt;/ul&gt;\n",
       "                    &lt;div class=&quot;m2g-gap&quot;&gt;&lt;/div&gt;\n",
       "\n",
       "                    &lt;!-- Sort dropdown --&gt;\n",
       "                    &lt;div class=&quot;m2g-dropdown m2g-sort&quot;&gt;\n",
       "                        &lt;select&gt;\n",
       "                            \n",
       "                            \n",
       "                                \n",
       "                                \n",
       "                                \n",
       "                            &lt;option value=&quot;mols2grid-id&quot; selected&gt;Index&lt;/option&gt;\n",
       "                                \n",
       "                            \n",
       "                                \n",
       "                                \n",
       "                                \n",
       "                            &lt;option value=&quot;data-Name&quot;&gt;Name&lt;/option&gt;\n",
       "                                \n",
       "                            \n",
       "                            \n",
       "                            &lt;option value=&quot;checkbox&quot;&gt;Selected&lt;/option&gt;\n",
       "                            \n",
       "                        &lt;/select&gt;\n",
       "                        &lt;div class=&quot;m2g-order&quot;&gt;&lt;/div&gt;\n",
       "                        &lt;div class=&quot;m2g-display&quot;&gt;\n",
       "                            Index\n",
       "                        &lt;/div&gt;\n",
       "                    &lt;/div&gt;\n",
       "                &lt;/div&gt;\n",
       "                &lt;div class=&quot;m2g-row&quot;&gt;\n",
       "                    &lt;!-- Search bar --&gt;\n",
       "                    &lt;div class=&quot;m2g-search-wrap&quot;&gt;\n",
       "                        &lt;input\n",
       "                            type=&quot;text&quot;\n",
       "                            class=&quot;m2g-searchbar form-control&quot;\n",
       "                            placeholder=&quot;Search&quot;\n",
       "                            aria-label=&quot;Search&quot;\n",
       "                            aria-describedby=&quot;basic-addon1&quot;\n",
       "                        /&gt;\n",
       "                        &lt;div class=&quot;m2g-search-options&quot;&gt;\n",
       "                            &lt;div class=&quot;m2g-option m2g-search-text sel&quot;&gt;Text&lt;/div&gt;\n",
       "                            &lt;div class=&quot;m2g-option m2g-search-smarts&quot;&gt;SMARTS&lt;/div&gt;\n",
       "                        &lt;/div&gt;\n",
       "                    &lt;/div&gt;\n",
       "\n",
       "                    &lt;!-- Action dropdown --&gt;\n",
       "                    &lt;div class=&quot;m2g-dropdown m2g-actions&quot;&gt;\n",
       "                        &lt;select&gt;\n",
       "                            &lt;option hidden&gt;-&lt;/option&gt;\n",
       "                            &lt;option value=&quot;select-all&quot;&gt;Select all&lt;/option&gt;\n",
       "                            &lt;option value=&quot;select-matching&quot;&gt;Select matching&lt;/option&gt;\n",
       "                            &lt;option value=&quot;unselect-all&quot;&gt;Unselect all&lt;/option&gt;\n",
       "                            &lt;option value=&quot;invert&quot;&gt;Invert&lt;/option&gt;\n",
       "                            &lt;option value=&quot;copy&quot;&gt;Copy to clipboard&lt;/option&gt;\n",
       "                            &lt;option value=&quot;save-smiles&quot;&gt;Save SMILES&lt;/option&gt;\n",
       "                            &lt;option value=&quot;save-csv&quot;&gt;Save CSV&lt;/option&gt;\n",
       "                        &lt;/select&gt;\n",
       "                        &lt;div class=&quot;m2g-icon&quot;&gt;\n",
       "                            &lt;svg width=&quot;20&quot; height=&quot;20&quot; viewBox=&quot;0 0 20 20&quot; xmlns=&quot;http://www.w3.org/2000/svg&quot;&gt;\n",
       "                                &lt;path d=&quot;M11.5 4C11.5 4.82843 10.8284 5.5 10 5.5C9.17157 5.5 8.5 4.82843 8.5 4C8.5 3.17157 9.17157 2.5 10 2.5C10.8284 2.5 11.5 3.17157 11.5 4ZM11.5 10C11.5 10.8284 10.8284 11.5 10 11.5C9.17157 11.5 8.5 10.8284 8.5 10C8.5 9.17157 9.17157 8.5 10 8.5C10.8284 8.5 11.5 9.17157 11.5 10ZM10 17.5C10.8284 17.5 11.5 16.8284 11.5 16C11.5 15.1716 10.8284 14.5 10 14.5C9.17157 14.5 8.5 15.1716 8.5 16C8.5 16.8284 9.17157 17.5 10 17.5Z&quot;/&gt;\n",
       "                            &lt;/svg&gt;\n",
       "                        &lt;/div&gt;\n",
       "                    &lt;/div&gt;\n",
       "                &lt;/div&gt;\n",
       "            &lt;/div&gt;\n",
       "\n",
       "            &lt;!-- Grid --&gt;\n",
       "            \n",
       "            &lt;div class=&quot;m2g-list&quot;&gt;&lt;div class=&quot;m2g-cell&quot; data-mols2grid-id=&quot;0&quot; tabindex=&quot;0&quot;&gt;&lt;div class=&quot;m2g-cb-wrap&quot;&gt;&lt;input type=&quot;checkbox&quot; tabindex=&quot;-1&quot; class=&quot;position-relative float-left cached_checkbox&quot;&gt;&lt;div class=&quot;m2g-cb&quot;&gt;&lt;/div&gt;&lt;div class=&quot;data-mols2grid-id-display&quot;&gt;&lt;/div&gt;&lt;/div&gt;&lt;div class=&quot;m2g-cell-actions&quot;&gt;&lt;/div&gt;&lt;div class=&quot;data data-img copy-me&quot;&gt;&lt;/div&gt;&lt;div class=&quot;data data-Name copy-me&quot;&gt;&lt;/div&gt;&lt;div class=&quot;data data-SMILES copy-me&quot; style=&quot;display: none;&quot;&gt;&lt;/div&gt;&lt;/div&gt;&lt;/div&gt;\n",
       "        &lt;/div&gt;\n",
       "        &lt;script&gt;\n",
       "            // list.js\n",
       "var listObj = new List(&#x27;mols2grid&#x27;, {\n",
       "    listClass: &#x27;m2g-list&#x27;,\n",
       "    valueNames: [{data: [&#x27;mols2grid-id&#x27;]}, &#x27;data-SMILES&#x27;, &#x27;data-mols2grid-id&#x27;, &#x27;data-Name&#x27;, &#x27;data-img&#x27;, &#x27;data-mols2grid-id-display&#x27;],\n",
       "    item: &#x27;&lt;div class=&quot;m2g-cell&quot; data-mols2grid-id=&quot;0&quot; tabindex=&quot;0&quot;&gt;&lt;div class=&quot;m2g-cb-wrap&quot;&gt;&lt;input type=&quot;checkbox&quot; tabindex=&quot;-1&quot; class=&quot;position-relative float-left cached_checkbox&quot;&gt;&lt;div class=&quot;m2g-cb&quot;&gt;&lt;/div&gt;&lt;div class=&quot;data-mols2grid-id-display&quot;&gt;&lt;/div&gt;&lt;/div&gt;&lt;div class=&quot;m2g-cell-actions&quot;&gt;&lt;/div&gt;&lt;div class=&quot;data data-img copy-me&quot;&gt;&lt;/div&gt;&lt;div class=&quot;data data-Name copy-me&quot;&gt;&lt;/div&gt;&lt;div class=&quot;data data-SMILES copy-me&quot; style=&quot;display: none;&quot;&gt;&lt;/div&gt;&lt;/div&gt;&#x27;,\n",
       "    page: 24,\n",
       "    pagination: {\n",
       "        paginationClass: &quot;m2g-pagination&quot;,\n",
       "        item: &#x27;&lt;li class=&quot;page-item&quot;&gt;&lt;a class=&quot;page page-link&quot; href=&quot;#&quot; onclick=&quot;event.preventDefault()&quot;&gt;&lt;/a&gt;&lt;/li&gt;&#x27;,\n",
       "        innerWindow: 1,\n",
       "        outerWindow: 1,\n",
       "    },\n",
       "});\n",
       "listObj.remove(&quot;mols2grid-id&quot;, &quot;0&quot;);\n",
       "listObj.add([{&quot;data-SMILES&quot;: &quot;CNC(=O)c1n[nH]c(N)n1&quot;, &quot;mols2grid-id&quot;: 0, &quot;data-Name&quot;: 19844301, &quot;data-img&quot;: null, &quot;data-mols2grid-id-display&quot;: 0}, {&quot;data-SMILES&quot;: &quot;N=C(N)CN1CC[C@H](O)C1&quot;, &quot;mols2grid-id&quot;: 1, &quot;data-Name&quot;: 203414649, &quot;data-img&quot;: null, &quot;data-mols2grid-id-display&quot;: 1}, {&quot;data-SMILES&quot;: &quot;COC[C@@H](O)CN&quot;, &quot;mols2grid-id&quot;: 2, &quot;data-Name&quot;: 2263862, &quot;data-img&quot;: null, &quot;data-mols2grid-id-display&quot;: 2}, {&quot;data-SMILES&quot;: &quot;NC(=O)CN1CCOCC1&quot;, &quot;mols2grid-id&quot;: 3, &quot;data-Name&quot;: 20436848, &quot;data-img&quot;: null, &quot;data-mols2grid-id-display&quot;: 3}, {&quot;data-SMILES&quot;: &quot;CNC(=S)NC(=N)N&quot;, &quot;mols2grid-id&quot;: 4, &quot;data-Name&quot;: 33691246, &quot;data-img&quot;: null, &quot;data-mols2grid-id-display&quot;: 4}, {&quot;data-SMILES&quot;: &quot;N[C@H]1COC[C@@H]1O&quot;, &quot;mols2grid-id&quot;: 5, &quot;data-Name&quot;: 12957834, &quot;data-img&quot;: null, &quot;data-mols2grid-id-display&quot;: 5}, {&quot;data-SMILES&quot;: &quot;CN(C)C[C@@H](N)C(=O)O&quot;, &quot;mols2grid-id&quot;: 6, &quot;data-Name&quot;: 35024242, &quot;data-img&quot;: null, &quot;data-mols2grid-id-display&quot;: 6}, {&quot;data-SMILES&quot;: &quot;Nc1nnn(CC(=O)O)n1&quot;, &quot;mols2grid-id&quot;: 7, &quot;data-Name&quot;: 4294607, &quot;data-img&quot;: null, &quot;data-mols2grid-id-display&quot;: 7}, {&quot;data-SMILES&quot;: &quot;NC(=O)c1ncc[nH]c1=O&quot;, &quot;mols2grid-id&quot;: 8, &quot;data-Name&quot;: 8657, &quot;data-img&quot;: null, &quot;data-mols2grid-id-display&quot;: 8}, {&quot;data-SMILES&quot;: &quot;N[C@H](CO)C(=O)O&quot;, &quot;mols2grid-id&quot;: 9, &quot;data-Name&quot;: 895342, &quot;data-img&quot;: null, &quot;data-mols2grid-id-display&quot;: 9}]);\n",
       "\n",
       "\n",
       "// filter\n",
       "if (window.parent.mols2grid_lists === undefined) {\n",
       "    window.parent.mols2grid_lists = {};\n",
       "}\n",
       "window.parent.mols2grid_lists[&quot;default&quot;] = listObj;\n",
       "\n",
       "\n",
       "// selection\n",
       "class MolStorage extends Map {\n",
       "    multi_set(_id, _smiles) {\n",
       "        for (let i = 0; i &lt; _id.length; i++) {\n",
       "            this.set(_id[i], _smiles[i])\n",
       "        }\n",
       "    }\n",
       "    multi_del(_id) {\n",
       "        for (let i = 0; i &lt; _id.length; i++) {\n",
       "            this.delete(_id[i])\n",
       "        }\n",
       "    }\n",
       "    to_dict() {\n",
       "        var content = &#x27;{&#x27;\n",
       "        for (let [key, value] of this) {\n",
       "            content += key + &#x27;:&#x27; + JSON.stringify(value) + &#x27;,&#x27;\n",
       "        }\n",
       "        content = content.length &gt; 1 ? content.slice(0, -1) : content\n",
       "        content += &#x27;}&#x27;\n",
       "        return content\n",
       "    }\n",
       "    to_keys() {\n",
       "        var content = []\n",
       "        for (let [key] of this) {\n",
       "            content.push(key)\n",
       "        }\n",
       "        return content\n",
       "    }\n",
       "    download_smi(fileName, allItems) {\n",
       "        var content = &#x27;&#x27;\n",
       "\n",
       "        if (allItems) {\n",
       "            // Gather all smiles\n",
       "            for (var item of allItems) {\n",
       "                var smiles = item.values()[&#x27;data-SMILES&#x27;]\n",
       "                var id = item.values()[&#x27;mols2grid-id&#x27;]\n",
       "                content += smiles + &#x27; &#x27; + id + &#x27;\\n&#x27;\n",
       "            }\n",
       "        } else {\n",
       "            // Gather selected smiles\n",
       "            for (let [key, value] of this) {\n",
       "                content += value + &#x27; &#x27; + key + &#x27;\\n&#x27;\n",
       "            }\n",
       "        }\n",
       "\n",
       "        var a = document.createElement(&#x27;a&#x27;)\n",
       "        var file = new Blob([content], { type: &#x27;text/plain&#x27; })\n",
       "        a.href = URL.createObjectURL(file)\n",
       "        a.download = fileName\n",
       "        a.click()\n",
       "        a.remove()\n",
       "    }\n",
       "}\n",
       "var SELECTION = new MolStorage();\n",
       "\n",
       "\n",
       "\n",
       "// kernel\n",
       "function add_selection(grid_id, _id, smiles) {\n",
       "    SELECTION.multi_set(_id, smiles);\n",
       "    let model = window.parent[&quot;_MOLS2GRID_&quot; + grid_id];\n",
       "    if (model) {\n",
       "        model.set(&quot;selection&quot;, SELECTION.to_dict());\n",
       "        model.save_changes();\n",
       "    }\n",
       "}\n",
       "function del_selection(grid_id, _id) {\n",
       "    SELECTION.multi_del(_id);\n",
       "    let model = window.parent[&quot;_MOLS2GRID_&quot; + grid_id];\n",
       "    if (model) {\n",
       "        model.set(&quot;selection&quot;, SELECTION.to_dict());\n",
       "        model.save_changes();\n",
       "    }\n",
       "}\n",
       "if (window.parent.IPython !== undefined) {\n",
       "    // Jupyter notebook\n",
       "    var kernel_env = &quot;jupyter&quot;;\n",
       "} else if (window.parent.google !== undefined) {\n",
       "    // Google colab\n",
       "    var kernel_env = &quot;colab&quot;;\n",
       "} else {\n",
       "    var kernel_env = null;\n",
       "}\n",
       "\n",
       "\n",
       "\n",
       "\n",
       "// sort\n",
       "var sortField = &#x27;mols2grid-id&#x27;\n",
       "var sortOrder = &#x27;asc&#x27;\n",
       "\n",
       "// Sort dropdown\n",
       "$(&#x27;#mols2grid .m2g-sort select&#x27;).change(sort)\n",
       "\n",
       "// Sort order\n",
       "$(&#x27;#mols2grid .m2g-order&#x27;).click(flipSort)\n",
       "\n",
       "function sort(e) {\n",
       "    if (e) {\n",
       "        sortField = e.target.value\n",
       "        var selectedOption = e.target.options[e.target.selectedIndex]\n",
       "        var sortFieldDisplay = selectedOption.text\n",
       "    }\n",
       "\n",
       "    // Sort\n",
       "    if (sortField == &#x27;checkbox&#x27;) {\n",
       "        listObj.sort(&#x27;mols2grid-id&#x27;, {order: sortOrder, sortFunction: checkboxSort})\n",
       "    } else {\n",
       "        listObj.sort(sortField, {order: sortOrder, sortFunction: mols2gridSortFunction})\n",
       "    }\n",
       "\n",
       "    // Update UI.\n",
       "    $(this).parent().find(&#x27;.m2g-display&#x27;).text(sortFieldDisplay)\n",
       "}\n",
       "\n",
       "// prettier-ignore\n",
       "function flipSort() {\n",
       "    $(this).parent().removeClass(&#x27;m2d-arrow-&#x27; + sortOrder)\n",
       "    sortOrder = sortOrder === &#x27;desc&#x27; ? &#x27;asc&#x27; : &#x27;desc&#x27;\n",
       "    $(this).parent().addClass(&#x27;m2d-arrow-&#x27; + sortOrder)\n",
       "    sort()\n",
       "}\n",
       "\n",
       "function mols2gridSortFunction(itemA, itemB, options) {\n",
       "    var x = itemA.values()[options.valueName]\n",
       "    var y = itemB.values()[options.valueName]\n",
       "    if (typeof x === &#x27;number&#x27;) {\n",
       "        if (isFinite(x - y)) {\n",
       "            return x - y\n",
       "        } else {\n",
       "            return isFinite(x) ? -1 : 1\n",
       "        }\n",
       "    } else {\n",
       "        x = x ? x.toLowerCase() : x\n",
       "        y = y ? y.toLowerCase() : y\n",
       "        return x &lt; y ? -1 : x &gt; y ? 1 : 0\n",
       "    }\n",
       "}\n",
       "function checkboxSort(itemA, itemB, options) {\n",
       "    if (itemA.elm !== undefined) {\n",
       "        var checkedA = itemA.elm.querySelector(&#x27;input[type=checkbox]&#x27;).checked\n",
       "        if (itemB.elm !== undefined) {\n",
       "            var checkedB = itemB.elm.querySelector(&#x27;input[type=checkbox]&#x27;).checked\n",
       "            if (checkedA &amp;&amp; !checkedB) {\n",
       "                return -1\n",
       "            } else if (!checkedA &amp;&amp; checkedB) {\n",
       "                return 1\n",
       "            } else {\n",
       "                return 0\n",
       "            }\n",
       "        } else {\n",
       "            return -1\n",
       "        }\n",
       "    } else if (itemB.elm !== undefined) {\n",
       "        return 1\n",
       "    } else {\n",
       "        return 0\n",
       "    }\n",
       "}\n",
       "\n",
       "\n",
       "\n",
       "\n",
       "\n",
       "// grid interactions (select, click, tooltip, key events)\n",
       "// Check if selection UI is supported.\n",
       "var supportSelection = eval(&#x27;True&#x27;.toLowerCase());\n",
       "\n",
       "listObj.on(&quot;updated&quot;, initInteraction);\n",
       "\n",
       "// (Re)initialiuze all grid interaction every time the grid changes.\n",
       "function initInteraction(list) {\n",
       "    initCellClick()\n",
       "    initToolTip()\n",
       "    initKeyboard()\n",
       "    if (supportSelection) initCheckbox()\n",
       "\n",
       "\n",
       "    // Hide pagination if there is only one page.\n",
       "    if (listObj.matchingItems.length &lt;= listObj.page) {\n",
       "        $(&#x27;#mols2grid .m2g-pagination&#x27;).hide()\n",
       "    } else {\n",
       "        $(&#x27;#mols2grid .m2g-pagination&#x27;).show()\n",
       "    }\n",
       "\n",
       "    // Add a bunch of phantom cells.\n",
       "    // These are used as filler to make sure that\n",
       "    // no grid cells need to be resized when there&#x27;s\n",
       "    // not enough results to fill the row.\n",
       "    $(&#x27;#mols2grid .m2g-list&#x27;).append(&#x27;&lt;div class=&quot;m2g-cell m2g-phantom&quot;&gt;&lt;/div&gt;&#x27;.repeat(11));\n",
       "}\n",
       "\n",
       "// Cell click handler.\n",
       "function initCellClick() {\n",
       "    $(&#x27;#mols2grid .m2g-cell&#x27;).off(&#x27;click&#x27;).click(function(e) {\n",
       "        if ($(e.target).hasClass(&#x27;m2g-info&#x27;) || $(e.target).is(&#x27;:checkbox&#x27;)) {\n",
       "            // Info button / Checkbox --&gt; do nothing.\n",
       "        } else if ($(e.target).is(&#x27;div&#x27;) &amp;&amp; $(e.target).hasClass(&#x27;data&#x27;)) {\n",
       "            // Data string --&gt; copy text.\n",
       "            copyOnClick(e.target)\n",
       "        } else if ($(e.target).hasClass(&#x27;m2g-callback&#x27;)) {\n",
       "            // Callback button.\n",
       "            onCallbackButtonClick(e.target)\n",
       "        } else {\n",
       "            // Outside checkbox --&gt; toggle the checkbox.\n",
       "            if (supportSelection) {\n",
       "                var chkbox = $(this).find(&#x27;input:checkbox&#x27;)[0]\n",
       "                chkbox.checked = !chkbox.checked\n",
       "                $(chkbox).trigger(&#x27;change&#x27;)\n",
       "            }\n",
       "        }\n",
       "    })\n",
       "}\n",
       "\n",
       "// Store an element&#x27;s text content in the clipboard.\n",
       "function copyOnClick(target) {\n",
       "    var text = $(target).text()\n",
       "    navigator.clipboard.writeText(text)\n",
       "\n",
       "    // Blink the cell to indicate that the text was copied.\n",
       "    $(target).addClass(&#x27;m2g-copy-blink&#x27;)\n",
       "    setTimeout(function() {\n",
       "        $(target).removeClass(&#x27;m2g-copy-blink&#x27;)\n",
       "    }, 450)\n",
       "}\n",
       "\n",
       "// Keyboard actions.\n",
       "function initKeyboard() {\n",
       "    // Disable scroll when pressing UP/DOWN arrows\n",
       "    $(&#x27;#mols2grid .m2g-cell&#x27;).off(&#x27;keydown&#x27;).keydown(function(e) {\n",
       "        if (e.which == 38 || e.which == 40) {\n",
       "            e.preventDefault()\n",
       "        }\n",
       "    })\n",
       "\n",
       "    $(&#x27;#mols2grid .m2g-cell&#x27;).off(&#x27;keyup&#x27;).keyup(function(e) {\n",
       "        var chkbox = $(this).find(&#x27;input:checkbox&#x27;)[0]\n",
       "        if (e.which == 13) {\n",
       "            // ENTER: toggle\n",
       "            chkbox.checked = !chkbox.checked\n",
       "            $(chkbox).trigger(&#x27;change&#x27;)\n",
       "        } else if (e.which == 27 || e.which == 8) {\n",
       "            // ESC/BACKSPACE: unselect\n",
       "            chkbox.checked = false\n",
       "            $(chkbox).trigger(&#x27;change&#x27;)\n",
       "        } else if (e.which == 37) {\n",
       "            // LEFT\n",
       "            $(this).prev().focus()\n",
       "        } else if (e.which == 39) {\n",
       "            // RIGHT\n",
       "            $(this).next().focus()\n",
       "        } else if (e.which == 38 || e.which == 40) {\n",
       "            var containerWidth = $(this).parent().outerWidth()\n",
       "            var cellWidth = $(this).outerWidth() + parseInt($(this).css(&#x27;marginLeft&#x27;)) * 2\n",
       "            var columns = Math.round(containerWidth / cellWidth)\n",
       "            var index = $(this).index()\n",
       "            if (e.which == 38) {\n",
       "                // UP\n",
       "                var indexAbove = Math.max(index - columns, 0)\n",
       "                $(this).parent().children().eq(indexAbove).focus()\n",
       "            } else if (e.which == 40) {\n",
       "                // DOWN    \n",
       "                var total = $(this).parent().children().length\n",
       "                var indexBelow = Math.min(index + columns, total)\n",
       "                $(this).parent().children().eq(indexBelow).focus()\n",
       "            }\n",
       "        }\n",
       "    })\n",
       "}\n",
       "\n",
       "// Show tooltip when hovering the info icon.\n",
       "function initToolTip() {\n",
       "    $(&#x27;#mols2grid .m2g-info&#x27;).off(&#x27;mouseenter&#x27;).off(&#x27;mouseleave&#x27;).off(&#x27;click&#x27;).mouseenter(function() {\n",
       "        // Show on enter\n",
       "        $(this).closest(&#x27;.m2g-cell&#x27;).find(&#x27;.m2g-tooltip[data-toggle=&quot;popover&quot;]&#x27;).popover(&#x27;show&#x27;)\n",
       "        $(&#x27;body &gt; .popover&#x27;).click(function(e) {\n",
       "            if ($(e.target).hasClass(&#x27;copy-me&#x27;)) {\n",
       "                copyOnClick(e.target)\n",
       "            } else if ($(e.target).is(&#x27;button&#x27;)) {\n",
       "                \n",
       "            }\n",
       "        })\n",
       "    }).mouseleave(function() {\n",
       "        // Hide on leave, unless sticky.\n",
       "        if (!$(this).closest(&#x27;.m2g-cell&#x27;).hasClass(&#x27;m2g-keep-tooltip&#x27;)) {\n",
       "            $(this).closest(&#x27;.m2g-cell&#x27;).find(&#x27;.m2g-tooltip[data-toggle=&quot;popover&quot;]&#x27;).popover(&#x27;hide&#x27;)\n",
       "        }\n",
       "    }).click(function() {\n",
       "        // Toggle sticky on click.\n",
       "        $(this).closest(&#x27;.m2g-cell&#x27;).toggleClass(&#x27;m2g-keep-tooltip&#x27;)\n",
       "\n",
       "        // Hide tooltip when sticky was turned off.\n",
       "        if ($(this).closest(&#x27;.m2g-cell&#x27;).hasClass(&#x27;m2g-keep-tooltip&#x27;)) {\n",
       "            $(this).closest(&#x27;.m2g-cell&#x27;).find(&#x27;.m2g-tooltip[data-toggle=&quot;popover&quot;]&#x27;).popover(&#x27;show&#x27;)\n",
       "        } else if (!$(this).closest(&#x27;.m2g-cell&#x27;).hasClass(&#x27;m2g-keep-tooltip&#x27;)) {\n",
       "            $(this).closest(&#x27;.m2g-cell&#x27;).find(&#x27;.m2g-tooltip[data-toggle=&quot;popover&quot;]&#x27;).popover(&#x27;hide&#x27;)\n",
       "        }\n",
       "    })\n",
       "}\n",
       "\n",
       "// Update selection on checkbox click.\n",
       "function initCheckbox() {\n",
       "    $(&quot;input:checkbox&quot;).off(&#x27;change&#x27;).change(function() {\n",
       "        var _id = parseInt($(this).closest(&quot;.m2g-cell&quot;).attr(&quot;data-mols2grid-id&quot;));\n",
       "        if (this.checked) {\n",
       "            var _smiles = $($(this).closest(&quot;.m2g-cell&quot;).children(&quot;.data-SMILES&quot;)[0]).text();\n",
       "            add_selection(&quot;default&quot;, [_id], [_smiles]);\n",
       "        } else {\n",
       "            del_selection(&quot;default&quot;, [_id]);\n",
       "        }\n",
       "    });\n",
       "}\n",
       "\n",
       "// Callback button\n",
       "function onCallbackButtonClick(target) {\n",
       "    var data = {}\n",
       "    data[&quot;mols2grid-id&quot;] = parseInt($(target).closest(&quot;.m2g-cell&quot;)\n",
       "                                            .attr(&quot;data-mols2grid-id&quot;));\n",
       "    data[&quot;img&quot;] = $(target).parent().siblings(&quot;.data-img&quot;).eq(0).get(0).innerHTML;\n",
       "    $(target).parent().siblings(&quot;.data&quot;).not(&quot;.data-img&quot;).each(function() {\n",
       "        let name = this.className.split(&quot; &quot;)\n",
       "            .filter(cls =&gt; cls.startsWith(&quot;data-&quot;))[0]\n",
       "            .substring(5);\n",
       "        data[name] = this.innerHTML;\n",
       "    });\n",
       "\n",
       "    \n",
       "    // Call custom js callback.\n",
       "    None\n",
       "    \n",
       "}\n",
       "\n",
       "\n",
       "\n",
       "/**\n",
       " * Actions\n",
       " */\n",
       "\n",
       "// Listen to action dropdown.\n",
       "$(&#x27;#mols2grid .m2g-actions select&#x27;).change(function(e) {\n",
       "    var val = e.target.value\n",
       "    switch(val) {\n",
       "        case &#x27;select-all&#x27;:\n",
       "            selectAll()\n",
       "            break\n",
       "        case &#x27;select-matching&#x27;:\n",
       "            selectMatching()\n",
       "            break\n",
       "        case &#x27;unselect-all&#x27;:\n",
       "            unselectAll()\n",
       "            break\n",
       "        case &#x27;invert&#x27;:\n",
       "            invertSelection()\n",
       "            break\n",
       "        case &#x27;copy&#x27;:\n",
       "            copy()\n",
       "            break\n",
       "        case &#x27;save-smiles&#x27;:\n",
       "            saveSmiles()\n",
       "            break\n",
       "        case &#x27;save-csv&#x27;:\n",
       "            saveCSV()\n",
       "            break\n",
       "    }\n",
       "    $(this).val(&#x27;&#x27;) // Reset dropdown\n",
       "})\n",
       "\n",
       "// Check all.\n",
       "function selectAll(e) {\n",
       "    var _id = [];\n",
       "    var _smiles = [];\n",
       "    listObj.items.forEach(function (item) {\n",
       "        if (item.elm) {\n",
       "            item.elm.getElementsByTagName(&quot;input&quot;)[0].checked = true;\n",
       "        } else {\n",
       "            item.show()\n",
       "            item.elm.getElementsByTagName(&quot;input&quot;)[0].checked = true;\n",
       "            item.hide()\n",
       "        }\n",
       "        _id.push(item.values()[&quot;mols2grid-id&quot;]);\n",
       "        _smiles.push(item.values()[&quot;data-SMILES&quot;]);\n",
       "    });\n",
       "    add_selection(&quot;default&quot;, _id, _smiles);\n",
       "};\n",
       "\n",
       "\n",
       "// Check matching.\n",
       "function selectMatching(e) {\n",
       "    var _id = [];\n",
       "    var _smiles = [];\n",
       "    listObj.matchingItems.forEach(function (item) {\n",
       "        if (item.elm) {\n",
       "            item.elm.getElementsByTagName(&quot;input&quot;)[0].checked = true;\n",
       "        } else {\n",
       "            item.show()\n",
       "            item.elm.getElementsByTagName(&quot;input&quot;)[0].checked = true;\n",
       "            item.hide()\n",
       "        }\n",
       "        _id.push(item.values()[&quot;mols2grid-id&quot;]);\n",
       "        _smiles.push(item.values()[&quot;data-SMILES&quot;]);\n",
       "    });\n",
       "    add_selection(&quot;default&quot;, _id, _smiles);\n",
       "};\n",
       "\n",
       "// Uncheck all.\n",
       "function unselectAll(e) {\n",
       "    var _id = [];\n",
       "    listObj.items.forEach(function (item) {\n",
       "        if (item.elm) {\n",
       "            item.elm.getElementsByTagName(&quot;input&quot;)[0].checked = false;\n",
       "        } else {\n",
       "            item.show()\n",
       "            item.elm.getElementsByTagName(&quot;input&quot;)[0].checked = false;\n",
       "            item.hide()\n",
       "        }\n",
       "        _id.push(item.values()[&quot;mols2grid-id&quot;]);\n",
       "    });\n",
       "    del_selection(&quot;default&quot;, _id);\n",
       "};\n",
       "\n",
       "// Invert selection.\n",
       "function invertSelection(e) {\n",
       "    var _id_add = [];\n",
       "    var _id_del = [];\n",
       "    var _smiles = [];\n",
       "    listObj.items.forEach(function (item) {\n",
       "        if (item.elm) {\n",
       "            var chkbox = item.elm.getElementsByTagName(&quot;input&quot;)[0]\n",
       "            chkbox.checked = !chkbox.checked;\n",
       "        } else {\n",
       "            item.show()\n",
       "            var chkbox = item.elm.getElementsByTagName(&quot;input&quot;)[0]\n",
       "            chkbox.checked = !chkbox.checked;\n",
       "            item.hide()\n",
       "        }\n",
       "        if (chkbox.checked) {\n",
       "            _id_add.push(item.values()[&quot;mols2grid-id&quot;]);\n",
       "            _smiles.push(item.values()[&quot;data-SMILES&quot;]);\n",
       "        } else {\n",
       "            _id_del.push(item.values()[&quot;mols2grid-id&quot;]);\n",
       "        }\n",
       "    });\n",
       "    del_selection(&quot;default&quot;, _id_del);\n",
       "    add_selection(&quot;default&quot;, _id_add, _smiles);\n",
       "};\n",
       "\n",
       "// Copy to clipboard.\n",
       "function copy(e) {\n",
       "    // navigator.clipboard.writeText(SELECTION.to_dict());\n",
       "    content = _renderCSV(&#x27;\\t&#x27;)\n",
       "    navigator.clipboard.writeText(content)\n",
       "};\n",
       "\n",
       "// Export smiles.\n",
       "function saveSmiles(e) {\n",
       "    var fileName = &quot;selection.smi&quot;\n",
       "    if (SELECTION.size) {\n",
       "        // Download selected smiles\n",
       "        SELECTION.download_smi(fileName);\n",
       "    } else {\n",
       "        // Download all smiles\n",
       "        SELECTION.download_smi(fileName, listObj.items);\n",
       "    }\n",
       "};\n",
       "\n",
       "// Export CSV.\n",
       "function saveCSV(e) {\n",
       "    content = _renderCSV(&#x27;;&#x27;)\n",
       "    var a = document.createElement(&quot;a&quot;);\n",
       "    var file = new Blob([content], {type: &quot;text/csv&quot;});\n",
       "    a.href = URL.createObjectURL(file);\n",
       "    a.download = &quot;selection.csv&quot;;\n",
       "    a.click();\n",
       "    a.remove();\n",
       "};\n",
       "\n",
       "// Render CSV for export of clipboard.\n",
       "function _renderCSV(sep) {\n",
       "    // Same order as subset + tooltip\n",
       "    var columns = Array.from(listObj.items[0].elm.querySelectorAll(&quot;div.data&quot;))\n",
       "        .map(elm =&gt; elm.classList[1])\n",
       "        .filter(name =&gt; name !== &quot;data-img&quot;);\n",
       "    // Remove &#x27;data-&#x27; and img\n",
       "    var header = columns.map(name =&gt; name.slice(5));\n",
       "    // CSV content\n",
       "    header = [&quot;index&quot;].concat(header).join(sep);\n",
       "    var content = header + &quot;\\n&quot;;\n",
       "    listObj.items.forEach(function (item) {\n",
       "        let data = item.values();\n",
       "        let index = data[&quot;mols2grid-id&quot;];\n",
       "        if (SELECTION.has(index) || SELECTION.size === 0) {\n",
       "            content += index;\n",
       "            columns.forEach((key) =&gt; {\n",
       "                content += sep + data[key];\n",
       "            })\n",
       "            content += &quot;\\n&quot;;\n",
       "        }\n",
       "    });\n",
       "    return content\n",
       "}\n",
       "\n",
       "\n",
       "// generate images for the currently displayed molecules\n",
       "var draw_opts = {&quot;width&quot;: 130, &quot;height&quot;: 90};\n",
       "var json_draw_opts = JSON.stringify(draw_opts);\n",
       "\n",
       "var smarts_matches = {};\n",
       "\n",
       "// Load RDKit\n",
       "window\n",
       ".initRDKitModule()\n",
       ".then(function(RDKit) {\n",
       "    console.log(&#x27;RDKit version: &#x27;, RDKit.version());\n",
       "    window.RDKit = RDKit;\n",
       "    window.RDKitModule = RDKit;\n",
       "\n",
       "    // Searchbar\n",
       "    function SmartsSearch(query, columns) {\n",
       "    var smiles_col = columns[0];\n",
       "    smarts_matches = {};\n",
       "    var query = $(&#x27;#mols2grid .m2g-searchbar&#x27;).val();\n",
       "    var qmol = RDKit.get_qmol(query);\n",
       "    if (qmol.is_valid()) {\n",
       "        listObj.items.forEach(function (item) {\n",
       "            var smiles = item.values()[smiles_col]\n",
       "            var mol = RDKit.get_mol(smiles, &#x27;{&quot;removeHs&quot;: false }&#x27;);\n",
       "            if (mol.is_valid()) {\n",
       "                var results = mol.get_substruct_matches(qmol);\n",
       "                if (results === &quot;\\{\\}&quot;) {\n",
       "                    item.found = false;\n",
       "                } else {\n",
       "                    item.found = true;\n",
       "                    \n",
       "                    results = JSON.parse(results);\n",
       "                    \n",
       "                    var highlights = {&quot;atoms&quot;: [], &quot;bonds&quot;: []};\n",
       "                    results.forEach(function (match) {\n",
       "                        highlights[&quot;atoms&quot;].push(...match.atoms)\n",
       "                        highlights[&quot;bonds&quot;].push(...match.bonds)\n",
       "                    });\n",
       "                    \n",
       "                    var index = item.values()[&quot;mols2grid-id&quot;];\n",
       "                    smarts_matches[index] = highlights;\n",
       "                    \n",
       "                }\n",
       "            } else {\n",
       "                item.found = false;\n",
       "            }\n",
       "            mol.delete();\n",
       "        });\n",
       "    }\n",
       "    qmol.delete();\n",
       "}\n",
       "var search_type = &quot;Text&quot;;\n",
       "// Temporary fix for regex characters being escaped by list.js\n",
       "// This extends String.replace to ignore the regex pattern used by list.js and returns\n",
       "// the string unmodified. Other calls should not be affected, unless they use the exact\n",
       "// same pattern and replacement value.\n",
       "// TODO: remove once the issue is fixed in list.js and released\n",
       "String.prototype.replace = (function(_super) {\n",
       "    return function() {\n",
       "        if (\n",
       "            (arguments[0].toString() === &#x27;/[-[\\\\]{}()*+?.,\\\\\\\\^$|#]/g&#x27;)\n",
       "            &amp;&amp; (arguments[1] === &#x27;\\\\$&amp;&#x27;)\n",
       "        ) {\n",
       "            if (this.length === 0) {\n",
       "                return &#x27;&#x27;\n",
       "            }\n",
       "            return this\n",
       "        }\n",
       "        return _super.apply(this, arguments);\n",
       "    };         \n",
       "})(String.prototype.replace);\n",
       "\n",
       "// Switch search type (Text or SMARTS)\n",
       "$(&#x27;#mols2grid .m2g-search-options .m2g-option&#x27;).click(function() {\n",
       "    search_type = $(this).text();\n",
       "    $(&#x27;#mols2grid .m2g-search-options .m2g-option.sel&#x27;).removeClass(&quot;sel&quot;);\n",
       "    $(this).addClass(&quot;sel&quot;);\n",
       "});\n",
       "\n",
       "// Searchbar update event handler\n",
       "$(&#x27;#mols2grid .m2g-searchbar&#x27;).on(&quot;keyup&quot;, function(e) {\n",
       "    var query = e.target.value;\n",
       "    if (search_type === &quot;Text&quot;) {\n",
       "        smarts_matches = {};\n",
       "        listObj.search(query, [&#x27;data-mols2grid-id&#x27;, &#x27;data-Name&#x27;]);\n",
       "    } else {\n",
       "        listObj.search(query, [&quot;data-SMILES&quot;], SmartsSearch);\n",
       "    }\n",
       "});\n",
       "\n",
       "    \n",
       "    // Generate images for the currently displayed molecules.\n",
       "RDKit.prefer_coordgen(true);\n",
       "function draw_mol(smiles, index, template_mol) {\n",
       "    var mol = RDKit.get_mol(smiles, &#x27;{&quot;removeHs&quot;: false }&#x27;);\n",
       "    var svg = &quot;&quot;;\n",
       "    if (mol.is_valid()) {\n",
       "        var highlights = smarts_matches[index];\n",
       "        if (highlights) {\n",
       "            var details = Object.assign({}, draw_opts, highlights);\n",
       "            details = JSON.stringify(details);\n",
       "            mol.generate_aligned_coords(template_mol, true);\n",
       "        } else {\n",
       "            var details = json_draw_opts;\n",
       "        }\n",
       "        svg = mol.get_svg_with_highlights(details);\n",
       "    }\n",
       "    mol.delete();\n",
       "    if (svg == &quot;&quot;) {\n",
       "        return &#x27;&lt;svg width=&quot;130&quot; height=&quot;90&quot; xmlns=&quot;http://www.w3.org/2000/svg&quot; version=&quot;1.1&quot; viewBox=&quot;0 0 130 90&quot;&gt;&lt;/svg&gt;&#x27;;\n",
       "    }\n",
       "    return svg;\n",
       "}\n",
       "\n",
       "// Update images when the list is updated.\n",
       "listObj.on(&quot;updated&quot;, function (list) {\n",
       "    var query = $(&#x27;#mols2grid .m2g-searchbar&#x27;).val();\n",
       "    var template_mol;\n",
       "    if (query === &quot;&quot;) {\n",
       "        smarts_matches = {};\n",
       "        template_mol = null;\n",
       "    } else {\n",
       "        template_mol = RDKit.get_qmol(query);\n",
       "        template_mol.set_new_coords(true);\n",
       "    }\n",
       "    $(&#x27;#mols2grid .m2g-cell&#x27;).each(function() {\n",
       "        var $t = $(this);\n",
       "        var smiles = $t.children(&quot;.data-SMILES&quot;).first().text();\n",
       "        var index = parseInt(this.getAttribute(&quot;data-mols2grid-id&quot;));\n",
       "        var svg = draw_mol(smiles, index, template_mol);\n",
       "        $t.children(&quot;.data-img&quot;).html(svg);\n",
       "    });\n",
       "    if (template_mol) {\n",
       "        template_mol.delete();\n",
       "    }\n",
       "});\n",
       "    \n",
       "\n",
       "    // Trigger update to activate tooltips, draw images, setup callbacks...\n",
       "    listObj.update();\n",
       "    \n",
       "    // Set iframe height to fit content.\n",
       "    fitIframe(window.frameElement);\n",
       "});\n",
       "        &lt;/script&gt;\n",
       "\n",
       "\n",
       "\n",
       "\n",
       "    &lt;/body&gt;\n",
       "&lt;/html&gt;\n",
       "\">\n",
       "</iframe>"
      ],
      "text/plain": [
       "<IPython.core.display.HTML object>"
      ]
     },
     "execution_count": 11,
     "metadata": {},
     "output_type": "execute_result"
    }
   ],
   "source": [
    "mols2grid.display(amine_df,subset=[\"img\",\"Name\"])"
   ]
  },
  {
   "cell_type": "markdown",
   "id": "95a81251",
   "metadata": {},
   "source": [
    "Make lists of acids and amines to use for the enumeration. "
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 12,
   "id": "c6da934b",
   "metadata": {},
   "outputs": [],
   "source": [
    "acid_list = acid_df[['mol','Name']].values\n",
    "amine_list = amine_df[['mol','Name']].values"
   ]
  },
  {
   "cell_type": "markdown",
   "id": "aaa7443f",
   "metadata": {},
   "source": [
    "Define a function to enumerate a library. "
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 13,
   "id": "ae9cd2f3",
   "metadata": {},
   "outputs": [],
   "source": [
    "def enumerate_library(rxn_mol, reagent_lol):\n",
    "    prod_list = []\n",
    "    # itertools.product generates all combinations of reactants\n",
    "    for reagents in product(*reagent_lol):\n",
    "        mol_list = [x[0] for x in reagents]\n",
    "        name_list = [str(x[1]) for x in reagents]\n",
    "        name = \"_\".join(name_list)\n",
    "        prod = rxn_mol.RunReactants(mol_list)\n",
    "        if prod is not None and len(prod):\n",
    "            product_mol = prod[0][0]\n",
    "            Chem.SanitizeMol(product_mol)\n",
    "            prod_list.append([Chem.MolToSmiles(product_mol), name])\n",
    "    return prod_list"
   ]
  },
  {
   "cell_type": "markdown",
   "id": "39b00a2e",
   "metadata": {},
   "source": [
    "Enumerate the library"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 14,
   "id": "88417a77",
   "metadata": {},
   "outputs": [],
   "source": [
    "prod_list = enumerate_library(rxn_mol,[amine_list, acid_list])"
   ]
  },
  {
   "cell_type": "markdown",
   "id": "557a6a44",
   "metadata": {},
   "source": [
    "Put the products into a dataframe"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 15,
   "id": "243662f8",
   "metadata": {},
   "outputs": [],
   "source": [
    "prod_df = pd.DataFrame(prod_list,columns=[\"SMILES\",\"Name\"])"
   ]
  },
  {
   "cell_type": "markdown",
   "id": "48dee6c7",
   "metadata": {},
   "source": [
    "View the products"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 16,
   "id": "17dcacb3",
   "metadata": {},
   "outputs": [
    {
     "data": {
      "application/vnd.jupyter.widget-view+json": {
       "model_id": "c2a3632300bb4769a56b040d0d5512b6",
       "version_major": 2,
       "version_minor": 0
      },
      "text/plain": [
       "MolGridWidget()"
      ]
     },
     "metadata": {},
     "output_type": "display_data"
    },
    {
     "data": {
      "text/html": [
       "<style>\n",
       "    /* Some CSS to integrate with Jupyter more cleanly */\n",
       "    div.output_subarea {\n",
       "        /* Undo an unfortunate max-width parameter\n",
       "        that causes the output area to be too narrow\n",
       "        on smaller screens. */\n",
       "        max-width: none;\n",
       "\n",
       "        /* Align the table with the content */\n",
       "        padding: 0;\n",
       "\n",
       "        /* Let it breathe */\n",
       "        margin-top: 20px;\n",
       "    }\n",
       "</style>\n",
       "\n",
       "<iframe class=\"mols2grid-iframe\" frameborder=\"0\" width=\"100%\"\n",
       "    \n",
       "    \n",
       "    allow=\"clipboard-write\"\n",
       "    \n",
       "    \n",
       "    sandbox=\"allow-scripts allow-same-origin allow-downloads allow-popups allow-modals\"\n",
       "    \n",
       "    srcdoc=\"\n",
       "\n",
       "\n",
       "\n",
       "&lt;html lang=&quot;en&quot;&gt;\n",
       "    &lt;head&gt;\n",
       "        &lt;meta charset=&quot;UTF-8&quot; /&gt;\n",
       "        &lt;meta http-equiv=&quot;X-UA-Compatible&quot; content=&quot;IE=edge&quot; /&gt;\n",
       "        &lt;meta name=&quot;viewport&quot; content=&quot;width=device-width, initial-scale=1.0&quot; /&gt;\n",
       "        &lt;title&gt;Document!&lt;/title&gt;\n",
       "\n",
       "\n",
       "\n",
       "        &lt;style&gt;\n",
       "            /**\n",
       " * General styling\n",
       " */\n",
       "body {\n",
       "    font-family: &#x27;DejaVu&#x27;, sans-serif;\n",
       "}\n",
       "h1,h2,h3,h4 {\n",
       "    margin: 0 0 10px 0;\n",
       "}\n",
       "h1 {\n",
       "    font-size: 26px;\n",
       "}\n",
       "h2 {\n",
       "    font-size: 20px;\n",
       "    font-weight: 400;\n",
       "}\n",
       "h3 {\n",
       "\tfont-size: 16px;\n",
       "}\n",
       "p {\n",
       "    margin: 0 0 10px 0;\n",
       "}\n",
       "\n",
       "\n",
       "/* Remove body margin inside iframe */\n",
       "body.m2g-inside-iframe {\n",
       "    margin: 0;\n",
       "}\n",
       "\n",
       "/* In-cell text */\n",
       "#mols2grid .data:not(.data-img) {\n",
       "    height: 16px;\n",
       "    line-height: 16px;\n",
       "}\n",
       "/* Text truncation */\n",
       "#mols2grid .data {\n",
       "    /* Break text into multiple lines (default for static)... */\n",
       "    word-wrap: normal;\n",
       "\n",
       "    /* ...or truncate it (default for interactive). */\n",
       "    overflow: hidden;\n",
       "    white-space: nowrap;\n",
       "    text-overflow: ellipsis;\n",
       "}\n",
       "\n",
       "\n",
       "/**\n",
       " * Popover\n",
       " * - - -\n",
       " * Note: this is a bootstrap variable which is not namespaced.\n",
       " * To avoid any contamination, we only style it when the\n",
       " * x-placement parameter is set.\n",
       " */\n",
       ".popover[x-placement] {\n",
       "    font-family: &#x27;DejaVu&#x27;, sans-serif;\n",
       "    background: white;\n",
       "    border: solid 1px rgba(0,0,0,.2);\n",
       "    font-size: 12px;\n",
       "    padding: 10px;\n",
       "    border-radius: 5px;\n",
       "    box-shadow: 0 0 20px rgba(0,0,0,.15);\n",
       "    user-select: none;\n",
       "}\n",
       ".popover[x-placement] h3 {\n",
       "    margin: 0;\n",
       "}\n",
       ".popover[x-placement] .arrow {\n",
       "    width: 10px;\n",
       "    height: 10px;\n",
       "    background: #fff;\n",
       "    border: solid 1px rgba(0,0,0,.2);\n",
       "    box-sizing: border-box;\n",
       "    position: absolute;\n",
       "    transform-origin: 5px 5px;\n",
       "    clip-path: polygon(0 0, 100% 0, 100% 100%);\n",
       "}\n",
       ".popover[x-placement=&#x27;left&#x27;] .arrow {\n",
       "    transform: rotate(45deg);\n",
       "    top: 50%;\n",
       "    right: -5px;\n",
       "}\n",
       ".popover[x-placement=&#x27;right&#x27;] .arrow {\n",
       "    transform: rotate(-135deg);\n",
       "    top: 50%;\n",
       "    left: -5px;\n",
       "}\n",
       ".popover[x-placement=&#x27;top&#x27;] .arrow {\n",
       "    transform: rotate(135deg);\n",
       "    left: 50%;\n",
       "    bottom: -5px;\n",
       "}\n",
       ".popover[x-placement=&#x27;bottom&#x27;] .arrow {\n",
       "    transform: rotate(-45deg);\n",
       "    left: 50%;\n",
       "    top: -5px;\n",
       "}\n",
       "            body {\n",
       "    /* Colors */\n",
       "    --m2g-black: rgba(0,0,0,.75);\n",
       "    --m2g-black-soft: rgba(0,0,0,.35);\n",
       "    --m2g-black-10: rgba(0,0,0,.1);\n",
       "    --m2g-bg: #f6f6f6;\n",
       "    --m2g-border: solid 1px rgba(0,0,0,0.2);\n",
       "    --m2g-hl: #555; /* Highlight color */\n",
       "    --m2g-hl-shadow: inset 0 0 0 1px var(--m2g-hl); /* Inset 1px shadow to make border thicker */\n",
       "    --m2g-blue: #0f62fe;\n",
       "    --m2g-blue-soft: rgba(15,98,254,.2);\n",
       "\n",
       "    /* Icons */\n",
       "    --m2g-icn-triangle: url(&#x27;data:image/svg+xml;utf8,&lt;svg width=&quot;20&quot; fill=&quot;rgba(0,0,0,.75)&quot; height=&quot;20&quot; viewBox=&quot;0 0 20 20&quot; xmlns=&quot;http://www.w3.org/2000/svg&quot;&gt;&lt;path d=&quot;M9.5713 13.285L6.2543 7.757C6.0543 7.424 6.2953 7 6.6823 7L13.3173 7C13.7053 7 13.9463 7.424 13.7453 7.757L10.4283 13.285C10.2343 13.609 9.7653 13.609 9.5713 13.285Z&quot;/&gt;&lt;/svg&gt;&#x27;);\n",
       "    --m2g-icn-triangle-white: url(&#x27;data:image/svg+xml;utf8,&lt;svg width=&quot;20&quot; fill=&quot;white&quot; height=&quot;20&quot; viewBox=&quot;0 0 20 20&quot; xmlns=&quot;http://www.w3.org/2000/svg&quot;&gt;&lt;path d=&quot;M9.5713 13.285L6.2543 7.757C6.0543 7.424 6.2953 7 6.6823 7L13.3173 7C13.7053 7 13.9463 7.424 13.7453 7.757L10.4283 13.285C10.2343 13.609 9.7653 13.609 9.5713 13.285Z&quot;/&gt;&lt;/svg&gt;&#x27;);\n",
       "    --m2g-icn-cb-white: url(&#x27;data:image/svg+xml;utf8,&lt;svg width=&quot;16&quot; height=&quot;16&quot; viewBox=&quot;0 0 16 16&quot; fill=&quot;none&quot; stroke=&quot;white&quot; stroke-width=&quot;2.5&quot; stroke-linecap=&quot;round&quot; xmlns=&quot;http://www.w3.org/2000/svg&quot;&gt;&lt;path d=&quot;M4 7.65686L7 10.6569L12.6569 5.00001&quot;/&gt;&lt;/svg&gt;&#x27;);\n",
       "    \n",
       "    /* Border radius */\n",
       "    --m2g-br: 3px;\n",
       "    --m2g-br-l: var(--m2g-br) 0 0 var(--m2g-br); /* Left-only */\n",
       "    --m2g-br-r: 0 var(--m2g-br) var(--m2g-br) 0; /* Right-only */\n",
       "\n",
       "    /* Text */\n",
       "    --m2g-fs: 14px; /* UI font-size */\n",
       "    --m2g-fs-cell: 12px; /* Cell font-size */\n",
       "\n",
       "    /* Transition speeds */\n",
       "    --m2g-trans: 150ms;\n",
       "\n",
       "    /* Layout */\n",
       "    --m2g-h: 40px; /* Form element height */\n",
       "}\n",
       "\n",
       "/* Styling */\n",
       "#mols2grid {\n",
       "    font-family: &#x27;DejaVu&#x27;, sans-serif;\n",
       "    font-size: var(--m2g-fs);\n",
       "}\n",
       "\n",
       "/* Fixes */\n",
       "#mols2grid *,\n",
       "#mols2grid *::before,\n",
       "#mols2grid *::after {\n",
       "    box-sizing: border-box;\n",
       "    outline: none;\n",
       "}\n",
       "\n",
       "\n",
       "\n",
       "/**\n",
       " * Functions section\n",
       " */\n",
       "\n",
       "#mols2grid .m2g-functions {\n",
       "    display: flex;\n",
       "}\n",
       "#mols2grid .m2g-functions .m2g-row {\n",
       "    flex: 0;\n",
       "    display: flex;\n",
       "}\n",
       "\n",
       "/* Individual elements don&#x27;t scale */\n",
       "#mols2grid .m2g-functions .m2g-row &gt; * {\n",
       "    flex: 0 0;\n",
       "    margin-right: 10px;\n",
       "}\n",
       "#mols2grid .m2g-functions .m2g-row:last-child &gt; *:last-child {\n",
       "    margin-right: 0;\n",
       "}\n",
       "\n",
       "/* Row 1: pagination + gap + sort */\n",
       "#mols2grid .m2g-functions .m2g-row:first-child {\n",
       "    flex: 1; /* Scale */\n",
       "}\n",
       "#mols2grid .m2g-functions .m2g-gap {\n",
       "    /* The gap in between will scale, so the pagination\n",
       "    stays on the left, while the rest moves to the right */\n",
       "    flex: 1;\n",
       "    margin-right: 0;\n",
       "}\n",
       "\n",
       "\n",
       "\n",
       "/*\n",
       " * Pagination\n",
       " */\n",
       "\n",
       "#mols2grid ul.m2g-pagination {\n",
       "    /* Unset defaults */\n",
       "    list-style-type: none;\n",
       "    margin-block-start: 0;\n",
       "    margin-block-end: 0;\n",
       "    margin-inline-start: 0;\n",
       "    margin-inline-end: 0;\n",
       "    padding-inline-start: 0;\n",
       "\n",
       "    /* Custom */\n",
       "    display: flex;\n",
       "}\n",
       "#mols2grid ul.m2g-pagination li {\n",
       "    background: var(--m2g-bg) ;\n",
       "    border: var(--m2g-border);\n",
       "    height: var(--m2g-h);\n",
       "    min-width: calc(var(--m2g-h) + 1px);\n",
       "    position: relative;\n",
       "    user-select: none;\n",
       "    \n",
       "    /* Compensate for double border */\n",
       "    margin-right: -1px;\n",
       "    \n",
       "    /* Center text */\n",
       "    display: flex;\n",
       "    align-items: center;\n",
       "    justify-content: center;\n",
       "}\n",
       "#mols2grid ul.m2g-pagination li:last-child {\n",
       "    min-width: var(--m2g-h);\n",
       "}\n",
       "#mols2grid ul.m2g-pagination li a {\n",
       "    text-decoration: none;\n",
       "    color: var(--m2g-black);\n",
       "    padding: 0 10px;\n",
       "    width: 100%;\n",
       "    height: var(--m2g-h);\n",
       "    line-height: var(--m2g-h);\n",
       "    text-align: center;\n",
       "    /* Compensate for border so there&#x27;s no gap between click areas  */\n",
       "    margin: 0 -1px;\n",
       "}\n",
       "\n",
       "/* Corner shape */\n",
       "#mols2grid ul.m2g-pagination li:first-child {\n",
       "    border-radius: var(--m2g-br-l);\n",
       "}\n",
       "#mols2grid ul.m2g-pagination li:last-child {\n",
       "    border-radius: var(--m2g-br-r);\n",
       "    margin-right: 0;\n",
       "}\n",
       "\n",
       "/* Focus state */\n",
       "#mols2grid ul.m2g-pagination li:focus-within {\n",
       "    border-color: var(--m2g-hl);\n",
       "    box-shadow: var(--m2g-hl-shadow);\n",
       "    z-index: 1;\n",
       "}\n",
       "\n",
       "/* Active state */\n",
       "#mols2grid ul.m2g-pagination li.active {\n",
       "    background: var(--m2g-hl);\n",
       "    z-index: 1;\n",
       "}\n",
       "#mols2grid ul.m2g-pagination li.active a {\n",
       "    cursor: default;\n",
       "    color: #fff;\n",
       "}\n",
       "\n",
       "/* Disabled sate */\n",
       "#mols2grid ul.m2g-pagination li.disabled a {\n",
       "    cursor: default;\n",
       "    color: rgba(0,0,0,.25);\n",
       "    pointer-events: none;\n",
       "}\n",
       "\n",
       "\n",
       "\n",
       "/*\n",
       " * Dropdowns\n",
       " */\n",
       "\n",
       "#mols2grid ::placeholder {\n",
       "    color: var(--m2g-black-soft);\n",
       "}\n",
       "#mols2grid .m2g-dropdown {\n",
       "    height: var(--m2g-h);\n",
       "    background: var(--m2g-bg);\n",
       "    border: var(--m2g-border);\n",
       "    border-radius: var(--m2g-br);\n",
       "    position: relative;\n",
       "}\n",
       "#mols2grid .m2g-dropdown select {\n",
       "    -webkit-appearance: none;\n",
       "    -moz-appearance: none;\n",
       "    -ms-appearance: none;\n",
       "    appearance: none;\n",
       "    background: transparent;\n",
       "    border: none;\n",
       "    height: 100%;\n",
       "    padding: 0 13px;\n",
       "    min-width: 0;\n",
       "    max-width: 250px;\n",
       "    color: var(--m2g-black);\n",
       "    cursor: pointer;\n",
       "}\n",
       "\n",
       "/* Icon */\n",
       "#mols2grid .m2g-dropdown .m2g-icon {\n",
       "    width: 30px;\n",
       "    height: var(--m2g-h);\n",
       "    display: flex;\n",
       "    align-items: center;\n",
       "    justify-content: center;\n",
       "    position: absolute;\n",
       "    top: 0;\n",
       "    right: 0;\n",
       "    pointer-events: none;\n",
       "}\n",
       "#mols2grid .m2g-dropdown .m2g-icon svg:not(.m2g-stroke) {\n",
       "    fill: var(--m2g-black);\n",
       "}\n",
       "#mols2grid .m2g-dropdown .m2g-icon svg.m2g-stroke {\n",
       "    stroke: var(--m2g-black);\n",
       "}\n",
       "\n",
       "/* Display */\n",
       "/* We hide the native select element because\n",
       " * it is limited in styling. Instead, we display\n",
       " * the selected value in a div. */\n",
       "#mols2grid .m2g-dropdown .m2g-display {\n",
       "    position: absolute;\n",
       "    left: 0;\n",
       "    right: 0;\n",
       "    top: 0;\n",
       "    bottom: 0;\n",
       "    pointer-events: none;\n",
       "    color: var(--m2g-black);\n",
       "    line-height: var(--m2g-h);\n",
       "    padding: 0 25px 0 13px;\n",
       "\n",
       "    /* Truncate dropdown text */\n",
       "    white-space: nowrap;\n",
       "\ttext-overflow: ellipsis;\n",
       "\toverflow: hidden;\n",
       "}\n",
       "\n",
       "/* Focus state */\n",
       "#mols2grid .m2g-dropdown:focus-within {\n",
       "    border-color: var(--m2g-hl);\n",
       "    box-shadow: var(--m2g-hl-shadow);\n",
       "}\n",
       "\n",
       "\n",
       "\n",
       "/**\n",
       " * Action dropdown\n",
       " */\n",
       "\n",
       "#mols2grid .m2g-dropdown.m2g-actions {\n",
       "    width: var(--m2g-h);\n",
       "    padding: 0;\n",
       "}\n",
       "#mols2grid .m2g-dropdown.m2g-actions select {\n",
       "    opacity: 0;\n",
       "    width: var(--m2g-h);\n",
       "}\n",
       "#mols2grid .m2g-dropdown.m2g-actions .m2g-icon {\n",
       "    width: var(--m2g-h);\n",
       "}\n",
       "\n",
       "\n",
       "\n",
       "/*\n",
       " * Sort dropdown\n",
       " */\n",
       "\n",
       "#mols2grid .m2g-dropdown.m2g-sort {\n",
       "    flex: 0 0 200px;\n",
       "    width: 200px; /* Needed in addition to flex-basis for small sizes! */\n",
       "    border-radius: var(--m2g-br);\n",
       "    background: var(--m2g-bg);\n",
       "    display: flex;\n",
       "}\n",
       "\n",
       "/* Dropdown */\n",
       "#mols2grid .m2g-dropdown.m2g-sort select {\n",
       "    flex: 1 1;\n",
       "    opacity: 0;\n",
       "    /* padding-right: 70px; Space for &quot;Sort:&quot; */\n",
       "    box-sizing: border-box;\n",
       "}\n",
       "\n",
       "/* Sort order */\n",
       "#mols2grid .m2g-dropdown.m2g-sort .m2g-order {\n",
       "    background: var(--m2g-bg) var(--m2g-icn-triangle) no-repeat center;\n",
       "    flex: 0 0 30px;\n",
       "    height: 100%;\n",
       "    border-left: var(--m2g-border);\n",
       "    cursor: pointer;\n",
       "}\n",
       "#mols2grid .m2g-dropdown.m2g-sort.m2d-arrow-desc .m2g-order {\n",
       "    transform: rotate(180deg);\n",
       "    border-left: none;\n",
       "    border-right: var(--m2g-border);\n",
       "}\n",
       "\n",
       "/* Display */\n",
       "#mols2grid .m2g-dropdown.m2g-sort .m2g-display {\n",
       "    right: 31px;\n",
       "    padding-right: 13px;\n",
       "}\n",
       "#mols2grid .m2g-dropdown.m2g-sort .m2g-display::before {\n",
       "    content: &#x27;Sort: &#x27;;\n",
       "}\n",
       "\n",
       "/* Focus state */\n",
       "#mols2grid .m2g-dropdown.m2g-sort:focus-within .m2g-display,\n",
       "#mols2grid .m2g-dropdown.m2g-sort:focus-within .m2g-order {\n",
       "    background-color: transparent;\n",
       "}\n",
       "\n",
       "\n",
       "\n",
       "/*\n",
       " * Search bar\n",
       " */\n",
       "\n",
       "#mols2grid .m2g-search-wrap {\n",
       "    height: var(--m2g-h);\n",
       "    display: flex;\n",
       "    align-items: center;\n",
       "    justify-content: flex-end;\n",
       "    background: var(--m2g-bg);\n",
       "    border: var(--m2g-border);\n",
       "    border-radius: var(--m2g-br);\n",
       "}\n",
       "#mols2grid .m2g-searchbar {\n",
       "    width: 170px;\n",
       "    height: var(--m2g-h);\n",
       "    padding: 0 13px;\n",
       "    border: none;\n",
       "    color: var(--m2g-black);\n",
       "    cursor: text;\n",
       "    background: transparent;\n",
       "}\n",
       "\n",
       "/* Focus state */\n",
       "#mols2grid .m2g-search-wrap:focus-within {\n",
       "    border-color: var(--m2g-hl);\n",
       "    box-shadow: var(--m2g-hl-shadow);\n",
       "}\n",
       "\n",
       "/* Option buttons */\n",
       "#mols2grid .m2g-search-options {\n",
       "    font-size: 12px;\n",
       "    display: flex;\n",
       "    height: calc(1.5em + .75rem);\n",
       "    line-height: calc(1.5em + .75rem);\n",
       "    margin-right: 5px;\n",
       "    border-radius: var(--m2g-br);\n",
       "    color: var(--m2g-black);\n",
       "}\n",
       "#mols2grid .m2g-search-options .m2g-option {\n",
       "    background: var(--m2g-black-10);\n",
       "    padding: 0 13px;\n",
       "    cursor: default;\n",
       "    user-select: none;\n",
       "}\n",
       "#mols2grid .m2g-search-options .m2g-option:not(.sel) {\n",
       "    cursor: pointer;\n",
       "}\n",
       "#mols2grid .m2g-search-options .m2g-option:first-child {\n",
       "    border-radius: 2px 0 0 2px;\n",
       "}\n",
       "#mols2grid .m2g-search-options .m2g-option:last-child {\n",
       "    border-radius: 0 2px 2px 0;\n",
       "}\n",
       "#mols2grid .m2g-search-options .m2g-option.sel {\n",
       "    background: var(--m2g-hl);\n",
       "    color: #fff;\n",
       "}\n",
       "\n",
       "\n",
       "\n",
       "/**\n",
       " * Grid\n",
       " */\n",
       "\n",
       "/* Container */\n",
       "#mols2grid .m2g-list {\n",
       "    display: flex;\n",
       "    flex-wrap: wrap;\n",
       "    align-items: flex-start;\n",
       "    justify-content: flex-start;\n",
       "    padding: 1px; /* Compensate for negative padding on cell */\n",
       "    user-select: none;\n",
       "    margin: 0px;\n",
       "    margin-top: 20px;\n",
       "    font-family: &#x27;DejaVu&#x27;, sans-serif;\n",
       "    \n",
       "}\n",
       "\n",
       "/* Cell */\n",
       "#mols2grid .m2g-cell {\n",
       "    border: 1px solid #cccccc;\n",
       "    text-align: center;\n",
       "    vertical-align: top;\n",
       "    font-family: var(--font-family);\n",
       "    padding: 10px;\n",
       "    padding-top: max(10px, 20px);\n",
       "    margin: -1px -1px 0 0;\n",
       "    flex: 1 0 130px;\n",
       "    position: relative;\n",
       "    font-size: var(--m2g-fs-cell);\n",
       "    cursor: pointer;\n",
       "    color: var(--m2g-black);\n",
       "    overflow: hidden;\n",
       "    box-sizing: border-box;\n",
       "    background-color: white;\n",
       "}\n",
       "#mols2grid .m2g-cell:focus {\n",
       "    z-index: 1;\n",
       "    border-color: var(--m2g-hl);\n",
       "    box-shadow: var(--m2g-hl-shadow);\n",
       "}\n",
       "\n",
       "/* Phantom cells to maintain grid structure with less results */\n",
       "#mols2grid .m2g-cell.m2g-phantom {\n",
       "    border: none;\n",
       "    pointer-events: none;\n",
       "    height: 0;\n",
       "    padding: 0;\n",
       "}\n",
       "\n",
       "/* Checkbox &amp; ID */\n",
       "#mols2grid .m2g-cb-wrap {\n",
       "    position: absolute;\n",
       "    top: 3px;\n",
       "    left: 3px;\n",
       "    display: flex;\n",
       "    border-radius: 2px;\n",
       "    font-size: 0;\n",
       "    line-height: 0;\n",
       "    padding: 3px;\n",
       "    padding-right: 0;\n",
       "}\n",
       "#mols2grid .m2g-cb-wrap input[type=checkbox] {\n",
       "    display: none;\n",
       "}\n",
       "#mols2grid .m2g-cb-wrap input[type=checkbox] + .m2g-cb {\n",
       "\twidth: 16px;\n",
       "\theight: 16px;\n",
       "\tbox-sizing: border-box;\n",
       "\tbackground: #fff;\n",
       "\tborder: var(--m2g-border);\n",
       "\tborder-radius: 2px;\n",
       "    margin-right: 5px;\n",
       "}\n",
       "#mols2grid .m2g-cb-wrap input[type=checkbox]:checked + .m2g-cb {\n",
       "    border: none;\n",
       "    background-color: var(--m2g-blue);\n",
       "    background-image: var(--m2g-icn-cb-white);\n",
       "}\n",
       "#mols2grid .m2g-tooltip {\n",
       "    /* This is a div spanning full cell size where the\n",
       "    tooltip is rendered around, because you can&#x27;t attach\n",
       "    it to the parent due to list.js limitation. */\n",
       "    width: 100%;\n",
       "    height: 100%;\n",
       "    position: absolute;\n",
       "    left: 0;\n",
       "    top: 0;\n",
       "    z-index: -1;\n",
       "    pointer-events: none;\n",
       "    opacity: 0;\n",
       "}\n",
       "#mols2grid .m2g-cell:has(:checked) {\n",
       "    background: #ffd !important; /* Overrides user-set background color */\n",
       "}\n",
       "#mols2grid .data-mols2grid-id-display {\n",
       "    font-size: var(--m2g-fs-cell);\n",
       "    line-height: 16px;\n",
       "}\n",
       "#mols2grid .m2g-cb-wrap input[type=checkbox] + .data-mols2grid-id-display {\n",
       "    padding: 0 5px 0 5px;\n",
       "}\n",
       "#mols2grid .m2g-cb-wrap .data-name-display {\n",
       "    font-size: var(--m2g-fs);\n",
       "    line-height: 16px;\n",
       "}\n",
       "\n",
       "/* Info + callback button wrap (28px high) */\n",
       "#mols2grid .m2g-cell-actions {\n",
       "    position: absolute;\n",
       "    top: 0;\n",
       "    right: 0;\n",
       "    display: flex;\n",
       "    flex-direction: row;\n",
       "    font-size: 0;\n",
       "    line-height: 0;\n",
       "    \n",
       "    /* background: yellow; */\n",
       "}\n",
       "\n",
       "/* Info button */\n",
       "#mols2grid .m2g-info {\n",
       "    width: 28px;\n",
       "    height: 28px;\n",
       "    border-radius: 2px;\n",
       "    line-height: 28px;\n",
       "    font-size: min(14px, 12px);\n",
       "    font-family: Georgia, serif;\n",
       "    font-style: italic;\n",
       "    padding: 0;\n",
       "    text-align: center;\n",
       "}\n",
       "#mols2grid .m2g-keep-tooltip .m2g-info {\n",
       "    color: #fff;\n",
       "}\n",
       "#mols2grid .m2g-keep-tooltip .m2g-info::before {\n",
       "    content: &#x27;i&#x27;;\n",
       "    width: 18px;\n",
       "    height: 18px;\n",
       "    line-height: 18px;\n",
       "    background: var(--m2g-hl);\n",
       "    position: absolute;\n",
       "    left: 5px;\n",
       "    top: 5px;\n",
       "    border-radius: 9px;\n",
       "}\n",
       "\n",
       "/* Callback button */\n",
       "#mols2grid .m2g-callback {\n",
       "    width: 28px;\n",
       "    height: 28px;\n",
       "    cursor: pointer;\n",
       "}\n",
       "#mols2grid .m2g-callback::after {\n",
       "    content: &#x27;&#x27;;\n",
       "    display: block;\n",
       "    width: 16px;\n",
       "    height: 16px;\n",
       "    margin: 6px;\n",
       "    border: var(--m2g-border);\n",
       "    border-radius: 2px;\n",
       "    background: var(--m2g-bg) var(--m2g-icn-triangle) no-repeat center;\n",
       "    transform: rotate(-90deg);\n",
       "}\n",
       "\n",
       "/* Image */\n",
       "#mols2grid .m2g-cell .data-img {\n",
       "    padding: 0;\n",
       "}\n",
       "#mols2grid .m2g-cell img,\n",
       "#mols2grid .m2g-cell svg {\n",
       "    max-width: 100%;\n",
       "    height: auto;\n",
       "    padding: 0;\n",
       "}\n",
       "#mols2grid .m2g-cell svg &gt; rect:first-child {\n",
       "    /* Remove the SVG background */\n",
       "    fill: transparent !important;\n",
       "}\n",
       "\n",
       "/* Text below image */\n",
       ".m2g-copy-blink {\n",
       "    animation: m2g-blink var(--m2g-trans) 3;\n",
       "}\n",
       "@keyframes m2g-blink {\n",
       "    0% {\n",
       "        opacity: 1;\n",
       "    }\n",
       "    49% {\n",
       "        opacity: 1;\n",
       "    }\n",
       "    50% {\n",
       "        opacity: 0;\n",
       "    }\n",
       "    100% {\n",
       "        opacity: 0;\n",
       "    }\n",
       "}\n",
       "\n",
       "/* Copyable text */\n",
       ".copy-me {\n",
       "    position: relative;\n",
       "    cursor: pointer;\n",
       "}\n",
       "\n",
       "\n",
       "\n",
       "/**\n",
       " * Modal popup\n",
       " * - - -\n",
       " * Triggered by make_popup_callback()\n",
       " * See https://mols2grid.readthedocs.io/en/latest/notebooks/callbacks.html#Display-a-popup-containing-descriptors\n",
       " */\n",
       "\n",
       "/* Container */\n",
       "#m2g-modal-container {\n",
       "    display: flex;\n",
       "    align-items: center;\n",
       "    justify-content: center;\n",
       "    background: var(--m2g-black-10);\n",
       "    position: fixed;\n",
       "    top: 0;\n",
       "    left: 0;\n",
       "    z-index: 1;\n",
       "    width: 100%;\n",
       "    height: 100%;\n",
       "    \n",
       "    /* Transition */\n",
       "    opacity: 0;\n",
       "    transition: opacity var(--m2g-trans) linear;\n",
       "}\n",
       "\n",
       "/* Modal */\n",
       "#m2g-modal {\n",
       "    background: #fff;\n",
       "    border-radius: var(--m2g-br);\n",
       "    box-shadow: 0 0 30px var(--m2g-black-10);\n",
       "    padding: 20px;\n",
       "    position: relative;\n",
       "    max-width: calc(100% - 80px);\n",
       "    max-height: calc(100% - 80px);\n",
       "    display: flex;\n",
       "    flex-direction: column;\n",
       "    min-width: 26px;\n",
       "\n",
       "    /* Transition */\n",
       "    opacity: 0;\n",
       "    transform: translate(0, 5px);\n",
       "    transition: transform var(--m2g-trans) ease-in-out, opacity var(--m2g-trans) linear;\n",
       "}\n",
       "#m2g-modal .m2g-modal-header {\n",
       "    flex: 0 0 26px;\n",
       "    margin-bottom: 10px;\n",
       "}\n",
       "#m2g-modal .m2g-modal-header h2 {\n",
       "    margin-bottom: 0;\n",
       "}\n",
       "#m2g-modal .m2g-modal-header h2 + p {\n",
       "    font-size: 15px;\n",
       "}\n",
       "#m2g-modal .m2g-modal-body {\n",
       "    flex: 1;\n",
       "    position: relative;\n",
       "}\n",
       "\n",
       "/* Transition */\n",
       "#m2g-modal-container.show {\n",
       "    opacity: 1;\n",
       "}\n",
       "#m2g-modal-container.show #m2g-modal {\n",
       "    opacity: 1;\n",
       "    transform: translate(0, 0);\n",
       "}\n",
       "\n",
       "/* Header + close btn */\n",
       "#m2g-modal h2 {\n",
       "    line-height: 26px;\n",
       "    padding-right: 40px;\n",
       "    text-transform: capitalize;\n",
       "}\n",
       "#m2g-modal h3 {\n",
       "    \n",
       "}\n",
       "#m2g-modal button.close {\n",
       "    background: transparent;\n",
       "    padding: 0;\n",
       "    color: var(--m2g-black);\n",
       "    font-size: 1.5rem;\n",
       "    width: 40px;\n",
       "    height: 40px;\n",
       "    position: absolute;\n",
       "    top: 13px;\n",
       "    right: 13px;\n",
       "    border: none;\n",
       "}\n",
       "\n",
       "/* Image */\n",
       "#m2g-modal .svg-wrap svg {\n",
       "    max-width: 100%;\n",
       "    margin-bottom: 20px;\n",
       "}\n",
       "\n",
       "/* Separator */\n",
       "hr {\n",
       "    width: 100%;\n",
       "    height: 1px;\n",
       "    background: #ddd;\n",
       "    margin: 15px 0;\n",
       "    border: none;\n",
       "}\n",
       "\n",
       "\n",
       "\n",
       "/**\n",
       " * Hover states\n",
       " */\n",
       "@media (hover:hover) {\n",
       "    /* Pagination */\n",
       "    #mols2grid ul.m2g-pagination li:not(.active):not(.disabled):hover {\n",
       "        background: #f0f0f0;\n",
       "        z-index: 1;\n",
       "    }\n",
       "    #mols2grid ul.m2g-pagination li.active + li:hover {\n",
       "        /* Keeping the hover border consiistent */\n",
       "        margin-left: 1px;\n",
       "        border-left: none;\n",
       "        min-width: 40px;\n",
       "    }\n",
       "\n",
       "    /* Dropdowns &amp; search */\n",
       "    #mols2grid .m2g-dropdown:not(:focus-within):hover,\n",
       "    #mols2grid .m2g-search-wrap:not(:focus-within):hover,\n",
       "    #mols2grid .m2g-sort:not(:focus-within) .m2g-order:hover {\n",
       "        background-color: #f0f0f0;\n",
       "    }\n",
       "    #mols2grid .m2g-search-wrap:not(:focus-within):hover {\n",
       "        background: #fff;\n",
       "        border-color: rgba(0,0,0,.3);\n",
       "    }\n",
       "    /* Hocus pocus to have separate hover states for dropdown and arrow */\n",
       "    #mols2grid .m2g-dropdown.m2g-sort:not(:focus-within):hover .m2g-order:not(:hover) + .m2g-display {\n",
       "        background-color: transparent;\n",
       "    }\n",
       "\n",
       "    /* Search options */\n",
       "    #mols2grid .m2g-search-options .m2g-option:not(.sel):hover {\n",
       "        background: rgba(0,0,0,.15);\n",
       "    }\n",
       "\n",
       "    /* Grid */\n",
       "    /* Note: this is in an ::after pseudo element, so the transparent\n",
       "    hover color plays nice with the cell background color. */\n",
       "    #mols2grid .m2g-cell:hover::after {\n",
       "        content: &#x27;&#x27;;\n",
       "        width: 100%;\n",
       "        height: 100%;\n",
       "        position: absolute;\n",
       "        top: 0;\n",
       "        left: 0;\n",
       "        background-color: rgba(0,0,0,0.05);\n",
       "        pointer-events: none;\n",
       "    }\n",
       "\n",
       "    /* info button */\n",
       "    #mols2grid .m2g-info:hover::before {\n",
       "        content: &#x27;i&#x27;;\n",
       "        color: #fff;\n",
       "        width: 18px;\n",
       "        height: 18px;\n",
       "        line-height: 18px;\n",
       "        background: var(--m2g-hl);\n",
       "        position: absolute;\n",
       "        left: 5px;\n",
       "        top: 5px;\n",
       "        border-radius: 9px;\n",
       "    }\n",
       "    \n",
       "    /* Callback button */\n",
       "    #mols2grid .m2g-callback:hover::after {\n",
       "        background-color: var(--m2g-black);\n",
       "        background-image: var(--m2g-icn-triangle-white);\n",
       "        border-color: transparent;\n",
       "    }\n",
       "\n",
       "    /* Copyable text */\n",
       "    .copy-me:hover {\n",
       "        text-decoration: underline;\n",
       "        text-decoration-color: var(--m2g-blue);\n",
       "    }\n",
       "}\n",
       "\n",
       "\n",
       "\n",
       "/**\n",
       " * Responsive behavior.\n",
       " * - - -\n",
       " * Note: container queries won&#x27;t work in older browsers,\n",
       " * but this is purely aesthetical behavior so that&#x27;s ok.\n",
       " * https://caniuse.com/css-container-queries\n",
       " */\n",
       "\n",
       "/* This sets the msg-list div as reference container */\n",
       "#mols2grid {\n",
       "    container-type: inline-size;\n",
       "}\n",
       "\n",
       "\n",
       "\n",
       "/**\n",
       " * Functions section\n",
       " */\n",
       "\n",
       "/* When there&#x27;s not enough space to put everything in one row, we break it into two.\n",
       " * - - -\n",
       " * 870px = pagination 280 + sort 200 + search 300 + menu 40 + (3*10 gap) = 850 + 20 buffer.\n",
       " * Buffer required because the button width inside the search depends on the font.\n",
       " */\n",
       "@container (max-width: 870px) {\n",
       "    #mols2grid .m2g-functions {\n",
       "        flex-direction: column-reverse;\n",
       "        gap: 10px;\n",
       "    }\n",
       "    #mols2grid .m2g-functions .m2g-row:last-child {\n",
       "        justify-content: flex-end;\n",
       "    }\n",
       "    #mols2grid .m2g-functions .m2g-row:first-child *:last-child {\n",
       "        margin-right: 0;\n",
       "    }\n",
       "}\n",
       "\n",
       "/* When there&#x27;s not enough room for pagination + sort on one row,\n",
       " * we reduce the sort drodpwon width.\n",
       " */\n",
       "@container (max-width: 500px) {\n",
       "    #mols2grid .m2g-functions .m2g-sort {\n",
       "        width: 80px;\n",
       "        flex-basis: 80px;\n",
       "    }\n",
       "    #mols2grid .m2g-functions .m2g-sort .m2g-display {\n",
       "        font-size: 0;\n",
       "        line-height: 0;\n",
       "        padding-right: 0;\n",
       "    }\n",
       "    #mols2grid .m2g-functions .m2g-sort .m2g-display::before {\n",
       "        content: &#x27;Sort&#x27;;\n",
       "        font-size: var(--m2g-fs);\n",
       "        line-height: var(--m2g-h);\n",
       "    }\n",
       "}\n",
       "\n",
       "/* When there&#x27;s not enough room for pagination + reduced sort on one row,\n",
       " * we reduce the pagination width.\n",
       " */\n",
       "@container (max-width: 500px) {\n",
       "    /* We&#x27;re overriding min-width from different\n",
       "    locations, including responsive rules */\n",
       "    #mols2grid ul.m2g-pagination li,\n",
       "    #mols2grid ul.m2g-pagination li:last-child,\n",
       "    #mols2grid ul.m2g-pagination li.active + li:hover {\n",
       "        min-width: 0;\n",
       "    }\n",
       "}\n",
       "\n",
       "/* When there&#x27;s not enough room for searchbar + menu\n",
       " * we scale down the searchbar to fit the container.\n",
       " */\n",
       "@container (max-width: 370px) {\n",
       "    #mols2grid .m2g-functions .m2g-row .m2g-search-wrap {\n",
       "        flex: 1;\n",
       "    }\n",
       "    #mols2grid .m2g-searchbar {\n",
       "        width: calc(100% - 50px);\n",
       "    }\n",
       "    #mols2grid .m2g-search-options {\n",
       "        width: 50px;\n",
       "    }\n",
       "\n",
       "    /* Collapse options in T/M buttons */\n",
       "    #mols2grid .m2g-search-options .m2g-option {\n",
       "        width: 25px;\n",
       "        text-align: center;\n",
       "        padding: 0;\n",
       "        overflow: hidden;\n",
       "    }\n",
       "    #mols2grid .m2g-search-options .m2g-option:first-child::before {\n",
       "        content: &#x27;T\\A&#x27;\n",
       "    }\n",
       "    #mols2grid .m2g-search-options .m2g-option:last-child::before {\n",
       "        content: &#x27;S\\A&#x27;\n",
       "    }\n",
       "}\n",
       "\n",
       "\n",
       "\n",
       "/**\n",
       " * Grid\n",
       " */\n",
       "\n",
       "/* When there&#x27;s room for 5 columns, fall back to 4 */\n",
       "@container (min-width: 519px) and (max-width: 779px) {\n",
       "    #mols2grid .m2g-cell {\n",
       "        flex-basis: calc(100% / 4);\n",
       "    }\n",
       "}\n",
       "\n",
       "/* When there&#x27;s room for 7-11 columns, fall back to 6 */\n",
       "@container (min-width: 779px) and (max-width: 1559px) {\n",
       "    #mols2grid .m2g-cell {\n",
       "        flex-basis: calc(100% / 6);\n",
       "    }\n",
       "}\n",
       "\n",
       "/* When there&#x27;s room for 13+ columns, fall back to 12 */\n",
       "@container (min-width: 1559px) {\n",
       "    #mols2grid .m2g-cell {\n",
       "        flex-basis: calc(100% / 12);\n",
       "    }\n",
       "}\n",
       "\n",
       "            /* Custom CSS */\n",
       "            \n",
       "        &lt;/style&gt;\n",
       "        &lt;script src=&quot;https://cdnjs.cloudflare.com/ajax/libs/list.js/2.3.1/list.min.js&quot;&gt;&lt;/script&gt;\n",
       "&lt;script src=&quot;https://code.jquery.com/jquery-3.6.0.min.js&quot; integrity=&quot;sha256-/xUj+3OJU5yExlq6GSYGSHk7tPXikynS7ogEvDej/m4=&quot; crossorigin=&quot;anonymous&quot;&gt;&lt;/script&gt;\n",
       "&lt;script src=&quot;https://unpkg.com/@rdkit/rdkit@2022.3.1/Code/MinimalLib/dist/RDKit_minimal.js&quot;&gt;&lt;/script&gt;\n",
       "        &lt;script&gt;\n",
       "    // Set iframe height to fit content.\n",
       "    function fitIframe(iframe) {\n",
       "        // Ignore when there&#x27;s no iframe\n",
       "        if (!iframe) return\n",
       "\n",
       "        // Only fit height when no specific height was given.\n",
       "        if (iframe.getAttribute(&#x27;height&#x27;)) return;\n",
       "\n",
       "        // Initial fit + refit whenever the window width changes.\n",
       "        _fit()\n",
       "        $(window).on(&#x27;resize&#x27;, function() {\n",
       "            if (window.innerWidth != window.prevInnerWidth) {\n",
       "                window.prevInnerWidth = window.innerWidth\n",
       "                _fit();\n",
       "            }\n",
       "        })\n",
       "\n",
       "        // Fit iframe height to content height.\n",
       "        function _fit() {\n",
       "            var height = iframe.contentDocument.body.scrollHeight + 18 + &#x27;px&#x27;;\n",
       "            iframe.style.height = height;\n",
       "        }\n",
       "    }\n",
       "&lt;/script&gt;\n",
       "\n",
       "&lt;!-- prettier-ignore --&gt;\n",
       "&lt;script src=&quot;https://cdn.jsdelivr.net/npm/bootstrap@4.6.0/dist/js/bootstrap.bundle.min.js&quot; integrity=&quot;sha384-Piv4xVNRyMGpqkS2by6br4gNJ7DXjqk09RmUpJ8jgGtD7zP9yug3goQfGII0yAns&quot; crossorigin=&quot;anonymous&quot;&gt;&lt;/script&gt;\n",
       "        \n",
       "        &lt;!-- Custom header --&gt;\n",
       "        \n",
       "\n",
       "\n",
       "\n",
       "\n",
       "    &lt;/head&gt;\n",
       "    &lt;body class=&quot;m2g-inside-iframe&quot;&gt;\n",
       "\n",
       "\n",
       "\n",
       "        &lt;div id=&quot;mols2grid&quot; class=&quot;grid-default&quot;&gt;\n",
       "            &lt;!-- Pagination &amp; search --&gt;\n",
       "            &lt;div class=&quot;m2g-functions&quot;&gt;\n",
       "                \n",
       "                &lt;div class=&quot;m2g-row&quot;&gt;\n",
       "                    &lt;!-- Pagination --&gt;\n",
       "                    &lt;ul class=&quot;m2g-pagination&quot; class=&quot;d-flex&quot;&gt;&lt;/ul&gt;\n",
       "                    &lt;div class=&quot;m2g-gap&quot;&gt;&lt;/div&gt;\n",
       "\n",
       "                    &lt;!-- Sort dropdown --&gt;\n",
       "                    &lt;div class=&quot;m2g-dropdown m2g-sort&quot;&gt;\n",
       "                        &lt;select&gt;\n",
       "                            \n",
       "                            \n",
       "                                \n",
       "                                \n",
       "                                \n",
       "                            &lt;option value=&quot;mols2grid-id&quot; selected&gt;Index&lt;/option&gt;\n",
       "                                \n",
       "                            \n",
       "                                \n",
       "                                \n",
       "                                \n",
       "                            &lt;option value=&quot;data-Name&quot;&gt;Name&lt;/option&gt;\n",
       "                                \n",
       "                            \n",
       "                            \n",
       "                            &lt;option value=&quot;checkbox&quot;&gt;Selected&lt;/option&gt;\n",
       "                            \n",
       "                        &lt;/select&gt;\n",
       "                        &lt;div class=&quot;m2g-order&quot;&gt;&lt;/div&gt;\n",
       "                        &lt;div class=&quot;m2g-display&quot;&gt;\n",
       "                            Index\n",
       "                        &lt;/div&gt;\n",
       "                    &lt;/div&gt;\n",
       "                &lt;/div&gt;\n",
       "                &lt;div class=&quot;m2g-row&quot;&gt;\n",
       "                    &lt;!-- Search bar --&gt;\n",
       "                    &lt;div class=&quot;m2g-search-wrap&quot;&gt;\n",
       "                        &lt;input\n",
       "                            type=&quot;text&quot;\n",
       "                            class=&quot;m2g-searchbar form-control&quot;\n",
       "                            placeholder=&quot;Search&quot;\n",
       "                            aria-label=&quot;Search&quot;\n",
       "                            aria-describedby=&quot;basic-addon1&quot;\n",
       "                        /&gt;\n",
       "                        &lt;div class=&quot;m2g-search-options&quot;&gt;\n",
       "                            &lt;div class=&quot;m2g-option m2g-search-text sel&quot;&gt;Text&lt;/div&gt;\n",
       "                            &lt;div class=&quot;m2g-option m2g-search-smarts&quot;&gt;SMARTS&lt;/div&gt;\n",
       "                        &lt;/div&gt;\n",
       "                    &lt;/div&gt;\n",
       "\n",
       "                    &lt;!-- Action dropdown --&gt;\n",
       "                    &lt;div class=&quot;m2g-dropdown m2g-actions&quot;&gt;\n",
       "                        &lt;select&gt;\n",
       "                            &lt;option hidden&gt;-&lt;/option&gt;\n",
       "                            &lt;option value=&quot;select-all&quot;&gt;Select all&lt;/option&gt;\n",
       "                            &lt;option value=&quot;select-matching&quot;&gt;Select matching&lt;/option&gt;\n",
       "                            &lt;option value=&quot;unselect-all&quot;&gt;Unselect all&lt;/option&gt;\n",
       "                            &lt;option value=&quot;invert&quot;&gt;Invert&lt;/option&gt;\n",
       "                            &lt;option value=&quot;copy&quot;&gt;Copy to clipboard&lt;/option&gt;\n",
       "                            &lt;option value=&quot;save-smiles&quot;&gt;Save SMILES&lt;/option&gt;\n",
       "                            &lt;option value=&quot;save-csv&quot;&gt;Save CSV&lt;/option&gt;\n",
       "                        &lt;/select&gt;\n",
       "                        &lt;div class=&quot;m2g-icon&quot;&gt;\n",
       "                            &lt;svg width=&quot;20&quot; height=&quot;20&quot; viewBox=&quot;0 0 20 20&quot; xmlns=&quot;http://www.w3.org/2000/svg&quot;&gt;\n",
       "                                &lt;path d=&quot;M11.5 4C11.5 4.82843 10.8284 5.5 10 5.5C9.17157 5.5 8.5 4.82843 8.5 4C8.5 3.17157 9.17157 2.5 10 2.5C10.8284 2.5 11.5 3.17157 11.5 4ZM11.5 10C11.5 10.8284 10.8284 11.5 10 11.5C9.17157 11.5 8.5 10.8284 8.5 10C8.5 9.17157 9.17157 8.5 10 8.5C10.8284 8.5 11.5 9.17157 11.5 10ZM10 17.5C10.8284 17.5 11.5 16.8284 11.5 16C11.5 15.1716 10.8284 14.5 10 14.5C9.17157 14.5 8.5 15.1716 8.5 16C8.5 16.8284 9.17157 17.5 10 17.5Z&quot;/&gt;\n",
       "                            &lt;/svg&gt;\n",
       "                        &lt;/div&gt;\n",
       "                    &lt;/div&gt;\n",
       "                &lt;/div&gt;\n",
       "            &lt;/div&gt;\n",
       "\n",
       "            &lt;!-- Grid --&gt;\n",
       "            \n",
       "            &lt;div class=&quot;m2g-list&quot;&gt;&lt;div class=&quot;m2g-cell&quot; data-mols2grid-id=&quot;0&quot; tabindex=&quot;0&quot;&gt;&lt;div class=&quot;m2g-cb-wrap&quot;&gt;&lt;input type=&quot;checkbox&quot; tabindex=&quot;-1&quot; class=&quot;position-relative float-left cached_checkbox&quot;&gt;&lt;div class=&quot;m2g-cb&quot;&gt;&lt;/div&gt;&lt;div class=&quot;data-mols2grid-id-display&quot;&gt;&lt;/div&gt;&lt;/div&gt;&lt;div class=&quot;m2g-cell-actions&quot;&gt;&lt;/div&gt;&lt;div class=&quot;data data-img copy-me&quot;&gt;&lt;/div&gt;&lt;div class=&quot;data data-Name copy-me&quot;&gt;&lt;/div&gt;&lt;div class=&quot;data data-SMILES copy-me&quot; style=&quot;display: none;&quot;&gt;&lt;/div&gt;&lt;/div&gt;&lt;/div&gt;\n",
       "        &lt;/div&gt;\n",
       "        &lt;script&gt;\n",
       "            // list.js\n",
       "var listObj = new List(&#x27;mols2grid&#x27;, {\n",
       "    listClass: &#x27;m2g-list&#x27;,\n",
       "    valueNames: [{data: [&#x27;mols2grid-id&#x27;]}, &#x27;data-SMILES&#x27;, &#x27;data-mols2grid-id&#x27;, &#x27;data-Name&#x27;, &#x27;data-img&#x27;, &#x27;data-mols2grid-id-display&#x27;],\n",
       "    item: &#x27;&lt;div class=&quot;m2g-cell&quot; data-mols2grid-id=&quot;0&quot; tabindex=&quot;0&quot;&gt;&lt;div class=&quot;m2g-cb-wrap&quot;&gt;&lt;input type=&quot;checkbox&quot; tabindex=&quot;-1&quot; class=&quot;position-relative float-left cached_checkbox&quot;&gt;&lt;div class=&quot;m2g-cb&quot;&gt;&lt;/div&gt;&lt;div class=&quot;data-mols2grid-id-display&quot;&gt;&lt;/div&gt;&lt;/div&gt;&lt;div class=&quot;m2g-cell-actions&quot;&gt;&lt;/div&gt;&lt;div class=&quot;data data-img copy-me&quot;&gt;&lt;/div&gt;&lt;div class=&quot;data data-Name copy-me&quot;&gt;&lt;/div&gt;&lt;div class=&quot;data data-SMILES copy-me&quot; style=&quot;display: none;&quot;&gt;&lt;/div&gt;&lt;/div&gt;&#x27;,\n",
       "    page: 24,\n",
       "    pagination: {\n",
       "        paginationClass: &quot;m2g-pagination&quot;,\n",
       "        item: &#x27;&lt;li class=&quot;page-item&quot;&gt;&lt;a class=&quot;page page-link&quot; href=&quot;#&quot; onclick=&quot;event.preventDefault()&quot;&gt;&lt;/a&gt;&lt;/li&gt;&#x27;,\n",
       "        innerWindow: 1,\n",
       "        outerWindow: 1,\n",
       "    },\n",
       "});\n",
       "listObj.remove(&quot;mols2grid-id&quot;, &quot;0&quot;);\n",
       "listObj.add([{&quot;data-SMILES&quot;: &quot;CNC(=O)c1n[nH]c(NC(=O)[C@H](N)CNC(=N)N)n1&quot;, &quot;mols2grid-id&quot;: 0, &quot;data-Name&quot;: &quot;19844301_1576365&quot;, &quot;data-img&quot;: null, &quot;data-mols2grid-id-display&quot;: 0}, {&quot;data-SMILES&quot;: &quot;CNC(=O)c1n[nH]c(NC(=O)[C@H](N)CN(C)C)n1&quot;, &quot;mols2grid-id&quot;: 1, &quot;data-Name&quot;: &quot;19844301_35024242&quot;, &quot;data-img&quot;: null, &quot;data-mols2grid-id-display&quot;: 1}, {&quot;data-SMILES&quot;: &quot;CNC(=O)c1n[nH]c(NC(=O)Cn2nnc(N)n2)n1&quot;, &quot;mols2grid-id&quot;: 2, &quot;data-Name&quot;: &quot;19844301_4294607&quot;, &quot;data-img&quot;: null, &quot;data-mols2grid-id-display&quot;: 2}, {&quot;data-SMILES&quot;: &quot;CNC(=O)c1n[nH]c(NC(=O)C[C@H](O)C(=O)OC)n1&quot;, &quot;mols2grid-id&quot;: 3, &quot;data-Name&quot;: &quot;19844301_14585673&quot;, &quot;data-img&quot;: null, &quot;data-mols2grid-id-display&quot;: 3}, {&quot;data-SMILES&quot;: &quot;CNC(=O)c1n[nH]c(NC(=O)[C@@H](N)CNC(=N)N)n1&quot;, &quot;mols2grid-id&quot;: 4, &quot;data-Name&quot;: &quot;19844301_2384694&quot;, &quot;data-img&quot;: null, &quot;data-mols2grid-id-display&quot;: 4}, {&quot;data-SMILES&quot;: &quot;CNC(=O)c1n[nH]c(NC(=O)[C@H](N)CO)n1&quot;, &quot;mols2grid-id&quot;: 5, &quot;data-Name&quot;: &quot;19844301_895342&quot;, &quot;data-img&quot;: null, &quot;data-mols2grid-id-display&quot;: 5}, {&quot;data-SMILES&quot;: &quot;CNC(=O)c1n[nH]c(NC(=O)[C@@H](N)CCN)n1&quot;, &quot;mols2grid-id&quot;: 6, &quot;data-Name&quot;: &quot;19844301_52986906&quot;, &quot;data-img&quot;: null, &quot;data-mols2grid-id-display&quot;: 6}, {&quot;data-SMILES&quot;: &quot;CNC(=O)c1n[nH]c(NC(=O)[C@@H](N)[C@@H](C)O)n1&quot;, &quot;mols2grid-id&quot;: 7, &quot;data-Name&quot;: &quot;19844301_895103&quot;, &quot;data-img&quot;: null, &quot;data-mols2grid-id-display&quot;: 7}, {&quot;data-SMILES&quot;: &quot;CNC(=O)c1n[nH]c(NC(=O)CC[C@@H](N)C(N)=O)n1&quot;, &quot;mols2grid-id&quot;: 8, &quot;data-Name&quot;: &quot;19844301_2560808&quot;, &quot;data-img&quot;: null, &quot;data-mols2grid-id-display&quot;: 8}, {&quot;data-SMILES&quot;: &quot;CNC(=O)c1n[nH]c(NC(=O)CCNC(=O)CN)n1&quot;, &quot;mols2grid-id&quot;: 9, &quot;data-Name&quot;: &quot;19844301_1637970&quot;, &quot;data-img&quot;: null, &quot;data-mols2grid-id-display&quot;: 9}, {&quot;data-SMILES&quot;: &quot;N=C(N)NC[C@@H](N)C(=O)NC(=N)CN1CC[C@H](O)C1&quot;, &quot;mols2grid-id&quot;: 10, &quot;data-Name&quot;: &quot;203414649_1576365&quot;, &quot;data-img&quot;: null, &quot;data-mols2grid-id-display&quot;: 10}, {&quot;data-SMILES&quot;: &quot;CN(C)C[C@@H](N)C(=O)NC(=N)CN1CC[C@H](O)C1&quot;, &quot;mols2grid-id&quot;: 11, &quot;data-Name&quot;: &quot;203414649_35024242&quot;, &quot;data-img&quot;: null, &quot;data-mols2grid-id-display&quot;: 11}, {&quot;data-SMILES&quot;: &quot;N=C(CN1CC[C@H](O)C1)NC(=O)Cn1nnc(N)n1&quot;, &quot;mols2grid-id&quot;: 12, &quot;data-Name&quot;: &quot;203414649_4294607&quot;, &quot;data-img&quot;: null, &quot;data-mols2grid-id-display&quot;: 12}, {&quot;data-SMILES&quot;: &quot;COC(=O)[C@@H](O)CC(=O)NC(=N)CN1CC[C@H](O)C1&quot;, &quot;mols2grid-id&quot;: 13, &quot;data-Name&quot;: &quot;203414649_14585673&quot;, &quot;data-img&quot;: null, &quot;data-mols2grid-id-display&quot;: 13}, {&quot;data-SMILES&quot;: &quot;N=C(N)NC[C@H](N)C(=O)NC(=N)CN1CC[C@H](O)C1&quot;, &quot;mols2grid-id&quot;: 14, &quot;data-Name&quot;: &quot;203414649_2384694&quot;, &quot;data-img&quot;: null, &quot;data-mols2grid-id-display&quot;: 14}, {&quot;data-SMILES&quot;: &quot;N=C(CN1CC[C@H](O)C1)NC(=O)[C@H](N)CO&quot;, &quot;mols2grid-id&quot;: 15, &quot;data-Name&quot;: &quot;203414649_895342&quot;, &quot;data-img&quot;: null, &quot;data-mols2grid-id-display&quot;: 15}, {&quot;data-SMILES&quot;: &quot;N=C(CN1CC[C@H](O)C1)NC(=O)[C@@H](N)CCN&quot;, &quot;mols2grid-id&quot;: 16, &quot;data-Name&quot;: &quot;203414649_52986906&quot;, &quot;data-img&quot;: null, &quot;data-mols2grid-id-display&quot;: 16}, {&quot;data-SMILES&quot;: &quot;C[C@@H](O)[C@H](N)C(=O)NC(=N)CN1CC[C@H](O)C1&quot;, &quot;mols2grid-id&quot;: 17, &quot;data-Name&quot;: &quot;203414649_895103&quot;, &quot;data-img&quot;: null, &quot;data-mols2grid-id-display&quot;: 17}, {&quot;data-SMILES&quot;: &quot;N=C(CN1CC[C@H](O)C1)NC(=O)CC[C@@H](N)C(N)=O&quot;, &quot;mols2grid-id&quot;: 18, &quot;data-Name&quot;: &quot;203414649_2560808&quot;, &quot;data-img&quot;: null, &quot;data-mols2grid-id-display&quot;: 18}, {&quot;data-SMILES&quot;: &quot;N=C(CN1CC[C@H](O)C1)NC(=O)CCNC(=O)CN&quot;, &quot;mols2grid-id&quot;: 19, &quot;data-Name&quot;: &quot;203414649_1637970&quot;, &quot;data-img&quot;: null, &quot;data-mols2grid-id-display&quot;: 19}, {&quot;data-SMILES&quot;: &quot;COC[C@@H](O)CNC(=O)[C@H](N)CNC(=N)N&quot;, &quot;mols2grid-id&quot;: 20, &quot;data-Name&quot;: &quot;2263862_1576365&quot;, &quot;data-img&quot;: null, &quot;data-mols2grid-id-display&quot;: 20}, {&quot;data-SMILES&quot;: &quot;COC[C@@H](O)CNC(=O)[C@H](N)CN(C)C&quot;, &quot;mols2grid-id&quot;: 21, &quot;data-Name&quot;: &quot;2263862_35024242&quot;, &quot;data-img&quot;: null, &quot;data-mols2grid-id-display&quot;: 21}, {&quot;data-SMILES&quot;: &quot;COC[C@@H](O)CNC(=O)Cn1nnc(N)n1&quot;, &quot;mols2grid-id&quot;: 22, &quot;data-Name&quot;: &quot;2263862_4294607&quot;, &quot;data-img&quot;: null, &quot;data-mols2grid-id-display&quot;: 22}, {&quot;data-SMILES&quot;: &quot;COC[C@@H](O)CNC(=O)C[C@H](O)C(=O)OC&quot;, &quot;mols2grid-id&quot;: 23, &quot;data-Name&quot;: &quot;2263862_14585673&quot;, &quot;data-img&quot;: null, &quot;data-mols2grid-id-display&quot;: 23}, {&quot;data-SMILES&quot;: &quot;COC[C@@H](O)CNC(=O)[C@@H](N)CNC(=N)N&quot;, &quot;mols2grid-id&quot;: 24, &quot;data-Name&quot;: &quot;2263862_2384694&quot;, &quot;data-img&quot;: null, &quot;data-mols2grid-id-display&quot;: 24}, {&quot;data-SMILES&quot;: &quot;COC[C@@H](O)CNC(=O)[C@H](N)CO&quot;, &quot;mols2grid-id&quot;: 25, &quot;data-Name&quot;: &quot;2263862_895342&quot;, &quot;data-img&quot;: null, &quot;data-mols2grid-id-display&quot;: 25}, {&quot;data-SMILES&quot;: &quot;COC[C@@H](O)CNC(=O)[C@@H](N)CCN&quot;, &quot;mols2grid-id&quot;: 26, &quot;data-Name&quot;: &quot;2263862_52986906&quot;, &quot;data-img&quot;: null, &quot;data-mols2grid-id-display&quot;: 26}, {&quot;data-SMILES&quot;: &quot;COC[C@@H](O)CNC(=O)[C@@H](N)[C@@H](C)O&quot;, &quot;mols2grid-id&quot;: 27, &quot;data-Name&quot;: &quot;2263862_895103&quot;, &quot;data-img&quot;: null, &quot;data-mols2grid-id-display&quot;: 27}, {&quot;data-SMILES&quot;: &quot;COC[C@@H](O)CNC(=O)CC[C@@H](N)C(N)=O&quot;, &quot;mols2grid-id&quot;: 28, &quot;data-Name&quot;: &quot;2263862_2560808&quot;, &quot;data-img&quot;: null, &quot;data-mols2grid-id-display&quot;: 28}, {&quot;data-SMILES&quot;: &quot;COC[C@@H](O)CNC(=O)CCNC(=O)CN&quot;, &quot;mols2grid-id&quot;: 29, &quot;data-Name&quot;: &quot;2263862_1637970&quot;, &quot;data-img&quot;: null, &quot;data-mols2grid-id-display&quot;: 29}, {&quot;data-SMILES&quot;: &quot;N=C(N)NC[C@@H](N)C(=O)NC(=O)CN1CCOCC1&quot;, &quot;mols2grid-id&quot;: 30, &quot;data-Name&quot;: &quot;20436848_1576365&quot;, &quot;data-img&quot;: null, &quot;data-mols2grid-id-display&quot;: 30}, {&quot;data-SMILES&quot;: &quot;CN(C)C[C@@H](N)C(=O)NC(=O)CN1CCOCC1&quot;, &quot;mols2grid-id&quot;: 31, &quot;data-Name&quot;: &quot;20436848_35024242&quot;, &quot;data-img&quot;: null, &quot;data-mols2grid-id-display&quot;: 31}, {&quot;data-SMILES&quot;: &quot;Nc1nnn(CC(=O)NC(=O)CN2CCOCC2)n1&quot;, &quot;mols2grid-id&quot;: 32, &quot;data-Name&quot;: &quot;20436848_4294607&quot;, &quot;data-img&quot;: null, &quot;data-mols2grid-id-display&quot;: 32}, {&quot;data-SMILES&quot;: &quot;COC(=O)[C@@H](O)CC(=O)NC(=O)CN1CCOCC1&quot;, &quot;mols2grid-id&quot;: 33, &quot;data-Name&quot;: &quot;20436848_14585673&quot;, &quot;data-img&quot;: null, &quot;data-mols2grid-id-display&quot;: 33}, {&quot;data-SMILES&quot;: &quot;N=C(N)NC[C@H](N)C(=O)NC(=O)CN1CCOCC1&quot;, &quot;mols2grid-id&quot;: 34, &quot;data-Name&quot;: &quot;20436848_2384694&quot;, &quot;data-img&quot;: null, &quot;data-mols2grid-id-display&quot;: 34}, {&quot;data-SMILES&quot;: &quot;N[C@H](CO)C(=O)NC(=O)CN1CCOCC1&quot;, &quot;mols2grid-id&quot;: 35, &quot;data-Name&quot;: &quot;20436848_895342&quot;, &quot;data-img&quot;: null, &quot;data-mols2grid-id-display&quot;: 35}, {&quot;data-SMILES&quot;: &quot;NCC[C@H](N)C(=O)NC(=O)CN1CCOCC1&quot;, &quot;mols2grid-id&quot;: 36, &quot;data-Name&quot;: &quot;20436848_52986906&quot;, &quot;data-img&quot;: null, &quot;data-mols2grid-id-display&quot;: 36}, {&quot;data-SMILES&quot;: &quot;C[C@@H](O)[C@H](N)C(=O)NC(=O)CN1CCOCC1&quot;, &quot;mols2grid-id&quot;: 37, &quot;data-Name&quot;: &quot;20436848_895103&quot;, &quot;data-img&quot;: null, &quot;data-mols2grid-id-display&quot;: 37}, {&quot;data-SMILES&quot;: &quot;NC(=O)[C@H](N)CCC(=O)NC(=O)CN1CCOCC1&quot;, &quot;mols2grid-id&quot;: 38, &quot;data-Name&quot;: &quot;20436848_2560808&quot;, &quot;data-img&quot;: null, &quot;data-mols2grid-id-display&quot;: 38}, {&quot;data-SMILES&quot;: &quot;NCC(=O)NCCC(=O)NC(=O)CN1CCOCC1&quot;, &quot;mols2grid-id&quot;: 39, &quot;data-Name&quot;: &quot;20436848_1637970&quot;, &quot;data-img&quot;: null, &quot;data-mols2grid-id-display&quot;: 39}, {&quot;data-SMILES&quot;: &quot;CNC(=S)NC(=N)NC(=O)[C@H](N)CNC(=N)N&quot;, &quot;mols2grid-id&quot;: 40, &quot;data-Name&quot;: &quot;33691246_1576365&quot;, &quot;data-img&quot;: null, &quot;data-mols2grid-id-display&quot;: 40}, {&quot;data-SMILES&quot;: &quot;CNC(=S)NC(=N)NC(=O)[C@H](N)CN(C)C&quot;, &quot;mols2grid-id&quot;: 41, &quot;data-Name&quot;: &quot;33691246_35024242&quot;, &quot;data-img&quot;: null, &quot;data-mols2grid-id-display&quot;: 41}, {&quot;data-SMILES&quot;: &quot;CNC(=S)NC(=N)NC(=O)Cn1nnc(N)n1&quot;, &quot;mols2grid-id&quot;: 42, &quot;data-Name&quot;: &quot;33691246_4294607&quot;, &quot;data-img&quot;: null, &quot;data-mols2grid-id-display&quot;: 42}, {&quot;data-SMILES&quot;: &quot;CNC(=S)NC(=N)NC(=O)C[C@H](O)C(=O)OC&quot;, &quot;mols2grid-id&quot;: 43, &quot;data-Name&quot;: &quot;33691246_14585673&quot;, &quot;data-img&quot;: null, &quot;data-mols2grid-id-display&quot;: 43}, {&quot;data-SMILES&quot;: &quot;CNC(=S)NC(=N)NC(=O)[C@@H](N)CNC(=N)N&quot;, &quot;mols2grid-id&quot;: 44, &quot;data-Name&quot;: &quot;33691246_2384694&quot;, &quot;data-img&quot;: null, &quot;data-mols2grid-id-display&quot;: 44}, {&quot;data-SMILES&quot;: &quot;CNC(=S)NC(=N)NC(=O)[C@H](N)CO&quot;, &quot;mols2grid-id&quot;: 45, &quot;data-Name&quot;: &quot;33691246_895342&quot;, &quot;data-img&quot;: null, &quot;data-mols2grid-id-display&quot;: 45}, {&quot;data-SMILES&quot;: &quot;CNC(=S)NC(=N)NC(=O)[C@@H](N)CCN&quot;, &quot;mols2grid-id&quot;: 46, &quot;data-Name&quot;: &quot;33691246_52986906&quot;, &quot;data-img&quot;: null, &quot;data-mols2grid-id-display&quot;: 46}, {&quot;data-SMILES&quot;: &quot;CNC(=S)NC(=N)NC(=O)[C@@H](N)[C@@H](C)O&quot;, &quot;mols2grid-id&quot;: 47, &quot;data-Name&quot;: &quot;33691246_895103&quot;, &quot;data-img&quot;: null, &quot;data-mols2grid-id-display&quot;: 47}, {&quot;data-SMILES&quot;: &quot;CNC(=S)NC(=N)NC(=O)CC[C@@H](N)C(N)=O&quot;, &quot;mols2grid-id&quot;: 48, &quot;data-Name&quot;: &quot;33691246_2560808&quot;, &quot;data-img&quot;: null, &quot;data-mols2grid-id-display&quot;: 48}, {&quot;data-SMILES&quot;: &quot;CNC(=S)NC(=N)NC(=O)CCNC(=O)CN&quot;, &quot;mols2grid-id&quot;: 49, &quot;data-Name&quot;: &quot;33691246_1637970&quot;, &quot;data-img&quot;: null, &quot;data-mols2grid-id-display&quot;: 49}, {&quot;data-SMILES&quot;: &quot;N=C(N)NC[C@@H](N)C(=O)N[C@H]1COC[C@@H]1O&quot;, &quot;mols2grid-id&quot;: 50, &quot;data-Name&quot;: &quot;12957834_1576365&quot;, &quot;data-img&quot;: null, &quot;data-mols2grid-id-display&quot;: 50}, {&quot;data-SMILES&quot;: &quot;CN(C)C[C@@H](N)C(=O)N[C@H]1COC[C@@H]1O&quot;, &quot;mols2grid-id&quot;: 51, &quot;data-Name&quot;: &quot;12957834_35024242&quot;, &quot;data-img&quot;: null, &quot;data-mols2grid-id-display&quot;: 51}, {&quot;data-SMILES&quot;: &quot;Nc1nnn(CC(=O)N[C@H]2COC[C@@H]2O)n1&quot;, &quot;mols2grid-id&quot;: 52, &quot;data-Name&quot;: &quot;12957834_4294607&quot;, &quot;data-img&quot;: null, &quot;data-mols2grid-id-display&quot;: 52}, {&quot;data-SMILES&quot;: &quot;COC(=O)[C@@H](O)CC(=O)N[C@H]1COC[C@@H]1O&quot;, &quot;mols2grid-id&quot;: 53, &quot;data-Name&quot;: &quot;12957834_14585673&quot;, &quot;data-img&quot;: null, &quot;data-mols2grid-id-display&quot;: 53}, {&quot;data-SMILES&quot;: &quot;N=C(N)NC[C@H](N)C(=O)N[C@H]1COC[C@@H]1O&quot;, &quot;mols2grid-id&quot;: 54, &quot;data-Name&quot;: &quot;12957834_2384694&quot;, &quot;data-img&quot;: null, &quot;data-mols2grid-id-display&quot;: 54}, {&quot;data-SMILES&quot;: &quot;N[C@H](CO)C(=O)N[C@H]1COC[C@@H]1O&quot;, &quot;mols2grid-id&quot;: 55, &quot;data-Name&quot;: &quot;12957834_895342&quot;, &quot;data-img&quot;: null, &quot;data-mols2grid-id-display&quot;: 55}, {&quot;data-SMILES&quot;: &quot;NCC[C@H](N)C(=O)N[C@H]1COC[C@@H]1O&quot;, &quot;mols2grid-id&quot;: 56, &quot;data-Name&quot;: &quot;12957834_52986906&quot;, &quot;data-img&quot;: null, &quot;data-mols2grid-id-display&quot;: 56}, {&quot;data-SMILES&quot;: &quot;C[C@@H](O)[C@H](N)C(=O)N[C@H]1COC[C@@H]1O&quot;, &quot;mols2grid-id&quot;: 57, &quot;data-Name&quot;: &quot;12957834_895103&quot;, &quot;data-img&quot;: null, &quot;data-mols2grid-id-display&quot;: 57}, {&quot;data-SMILES&quot;: &quot;NC(=O)[C@H](N)CCC(=O)N[C@H]1COC[C@@H]1O&quot;, &quot;mols2grid-id&quot;: 58, &quot;data-Name&quot;: &quot;12957834_2560808&quot;, &quot;data-img&quot;: null, &quot;data-mols2grid-id-display&quot;: 58}, {&quot;data-SMILES&quot;: &quot;NCC(=O)NCCC(=O)N[C@H]1COC[C@@H]1O&quot;, &quot;mols2grid-id&quot;: 59, &quot;data-Name&quot;: &quot;12957834_1637970&quot;, &quot;data-img&quot;: null, &quot;data-mols2grid-id-display&quot;: 59}, {&quot;data-SMILES&quot;: &quot;CN(C)C[C@@H](NC(=O)[C@H](N)CNC(=N)N)C(=O)O&quot;, &quot;mols2grid-id&quot;: 60, &quot;data-Name&quot;: &quot;35024242_1576365&quot;, &quot;data-img&quot;: null, &quot;data-mols2grid-id-display&quot;: 60}, {&quot;data-SMILES&quot;: &quot;CN(C)C[C@@H](N)C(=O)N[C@H](CN(C)C)C(=O)O&quot;, &quot;mols2grid-id&quot;: 61, &quot;data-Name&quot;: &quot;35024242_35024242&quot;, &quot;data-img&quot;: null, &quot;data-mols2grid-id-display&quot;: 61}, {&quot;data-SMILES&quot;: &quot;CN(C)C[C@@H](NC(=O)Cn1nnc(N)n1)C(=O)O&quot;, &quot;mols2grid-id&quot;: 62, &quot;data-Name&quot;: &quot;35024242_4294607&quot;, &quot;data-img&quot;: null, &quot;data-mols2grid-id-display&quot;: 62}, {&quot;data-SMILES&quot;: &quot;COC(=O)[C@@H](O)CC(=O)N[C@H](CN(C)C)C(=O)O&quot;, &quot;mols2grid-id&quot;: 63, &quot;data-Name&quot;: &quot;35024242_14585673&quot;, &quot;data-img&quot;: null, &quot;data-mols2grid-id-display&quot;: 63}, {&quot;data-SMILES&quot;: &quot;CN(C)C[C@@H](NC(=O)[C@@H](N)CNC(=N)N)C(=O)O&quot;, &quot;mols2grid-id&quot;: 64, &quot;data-Name&quot;: &quot;35024242_2384694&quot;, &quot;data-img&quot;: null, &quot;data-mols2grid-id-display&quot;: 64}, {&quot;data-SMILES&quot;: &quot;CN(C)C[C@@H](NC(=O)[C@H](N)CO)C(=O)O&quot;, &quot;mols2grid-id&quot;: 65, &quot;data-Name&quot;: &quot;35024242_895342&quot;, &quot;data-img&quot;: null, &quot;data-mols2grid-id-display&quot;: 65}, {&quot;data-SMILES&quot;: &quot;CN(C)C[C@@H](NC(=O)[C@@H](N)CCN)C(=O)O&quot;, &quot;mols2grid-id&quot;: 66, &quot;data-Name&quot;: &quot;35024242_52986906&quot;, &quot;data-img&quot;: null, &quot;data-mols2grid-id-display&quot;: 66}, {&quot;data-SMILES&quot;: &quot;C[C@@H](O)[C@H](N)C(=O)N[C@H](CN(C)C)C(=O)O&quot;, &quot;mols2grid-id&quot;: 67, &quot;data-Name&quot;: &quot;35024242_895103&quot;, &quot;data-img&quot;: null, &quot;data-mols2grid-id-display&quot;: 67}, {&quot;data-SMILES&quot;: &quot;CN(C)C[C@@H](NC(=O)CC[C@@H](N)C(N)=O)C(=O)O&quot;, &quot;mols2grid-id&quot;: 68, &quot;data-Name&quot;: &quot;35024242_2560808&quot;, &quot;data-img&quot;: null, &quot;data-mols2grid-id-display&quot;: 68}, {&quot;data-SMILES&quot;: &quot;CN(C)C[C@@H](NC(=O)CCNC(=O)CN)C(=O)O&quot;, &quot;mols2grid-id&quot;: 69, &quot;data-Name&quot;: &quot;35024242_1637970&quot;, &quot;data-img&quot;: null, &quot;data-mols2grid-id-display&quot;: 69}, {&quot;data-SMILES&quot;: &quot;N=C(N)NC[C@@H](N)C(=O)Nc1nnn(CC(=O)O)n1&quot;, &quot;mols2grid-id&quot;: 70, &quot;data-Name&quot;: &quot;4294607_1576365&quot;, &quot;data-img&quot;: null, &quot;data-mols2grid-id-display&quot;: 70}, {&quot;data-SMILES&quot;: &quot;CN(C)C[C@@H](N)C(=O)Nc1nnn(CC(=O)O)n1&quot;, &quot;mols2grid-id&quot;: 71, &quot;data-Name&quot;: &quot;4294607_35024242&quot;, &quot;data-img&quot;: null, &quot;data-mols2grid-id-display&quot;: 71}, {&quot;data-SMILES&quot;: &quot;Nc1nnn(CC(=O)Nc2nnn(CC(=O)O)n2)n1&quot;, &quot;mols2grid-id&quot;: 72, &quot;data-Name&quot;: &quot;4294607_4294607&quot;, &quot;data-img&quot;: null, &quot;data-mols2grid-id-display&quot;: 72}, {&quot;data-SMILES&quot;: &quot;COC(=O)[C@@H](O)CC(=O)Nc1nnn(CC(=O)O)n1&quot;, &quot;mols2grid-id&quot;: 73, &quot;data-Name&quot;: &quot;4294607_14585673&quot;, &quot;data-img&quot;: null, &quot;data-mols2grid-id-display&quot;: 73}, {&quot;data-SMILES&quot;: &quot;N=C(N)NC[C@H](N)C(=O)Nc1nnn(CC(=O)O)n1&quot;, &quot;mols2grid-id&quot;: 74, &quot;data-Name&quot;: &quot;4294607_2384694&quot;, &quot;data-img&quot;: null, &quot;data-mols2grid-id-display&quot;: 74}, {&quot;data-SMILES&quot;: &quot;N[C@H](CO)C(=O)Nc1nnn(CC(=O)O)n1&quot;, &quot;mols2grid-id&quot;: 75, &quot;data-Name&quot;: &quot;4294607_895342&quot;, &quot;data-img&quot;: null, &quot;data-mols2grid-id-display&quot;: 75}, {&quot;data-SMILES&quot;: &quot;NCC[C@H](N)C(=O)Nc1nnn(CC(=O)O)n1&quot;, &quot;mols2grid-id&quot;: 76, &quot;data-Name&quot;: &quot;4294607_52986906&quot;, &quot;data-img&quot;: null, &quot;data-mols2grid-id-display&quot;: 76}, {&quot;data-SMILES&quot;: &quot;C[C@@H](O)[C@H](N)C(=O)Nc1nnn(CC(=O)O)n1&quot;, &quot;mols2grid-id&quot;: 77, &quot;data-Name&quot;: &quot;4294607_895103&quot;, &quot;data-img&quot;: null, &quot;data-mols2grid-id-display&quot;: 77}, {&quot;data-SMILES&quot;: &quot;NC(=O)[C@H](N)CCC(=O)Nc1nnn(CC(=O)O)n1&quot;, &quot;mols2grid-id&quot;: 78, &quot;data-Name&quot;: &quot;4294607_2560808&quot;, &quot;data-img&quot;: null, &quot;data-mols2grid-id-display&quot;: 78}, {&quot;data-SMILES&quot;: &quot;NCC(=O)NCCC(=O)Nc1nnn(CC(=O)O)n1&quot;, &quot;mols2grid-id&quot;: 79, &quot;data-Name&quot;: &quot;4294607_1637970&quot;, &quot;data-img&quot;: null, &quot;data-mols2grid-id-display&quot;: 79}, {&quot;data-SMILES&quot;: &quot;N=C(N)NC[C@@H](N)C(=O)NC(=O)c1ncc[nH]c1=O&quot;, &quot;mols2grid-id&quot;: 80, &quot;data-Name&quot;: &quot;8657_1576365&quot;, &quot;data-img&quot;: null, &quot;data-mols2grid-id-display&quot;: 80}, {&quot;data-SMILES&quot;: &quot;CN(C)C[C@@H](N)C(=O)NC(=O)c1ncc[nH]c1=O&quot;, &quot;mols2grid-id&quot;: 81, &quot;data-Name&quot;: &quot;8657_35024242&quot;, &quot;data-img&quot;: null, &quot;data-mols2grid-id-display&quot;: 81}, {&quot;data-SMILES&quot;: &quot;Nc1nnn(CC(=O)NC(=O)c2ncc[nH]c2=O)n1&quot;, &quot;mols2grid-id&quot;: 82, &quot;data-Name&quot;: &quot;8657_4294607&quot;, &quot;data-img&quot;: null, &quot;data-mols2grid-id-display&quot;: 82}, {&quot;data-SMILES&quot;: &quot;COC(=O)[C@@H](O)CC(=O)NC(=O)c1ncc[nH]c1=O&quot;, &quot;mols2grid-id&quot;: 83, &quot;data-Name&quot;: &quot;8657_14585673&quot;, &quot;data-img&quot;: null, &quot;data-mols2grid-id-display&quot;: 83}, {&quot;data-SMILES&quot;: &quot;N=C(N)NC[C@H](N)C(=O)NC(=O)c1ncc[nH]c1=O&quot;, &quot;mols2grid-id&quot;: 84, &quot;data-Name&quot;: &quot;8657_2384694&quot;, &quot;data-img&quot;: null, &quot;data-mols2grid-id-display&quot;: 84}, {&quot;data-SMILES&quot;: &quot;N[C@H](CO)C(=O)NC(=O)c1ncc[nH]c1=O&quot;, &quot;mols2grid-id&quot;: 85, &quot;data-Name&quot;: &quot;8657_895342&quot;, &quot;data-img&quot;: null, &quot;data-mols2grid-id-display&quot;: 85}, {&quot;data-SMILES&quot;: &quot;NCC[C@H](N)C(=O)NC(=O)c1ncc[nH]c1=O&quot;, &quot;mols2grid-id&quot;: 86, &quot;data-Name&quot;: &quot;8657_52986906&quot;, &quot;data-img&quot;: null, &quot;data-mols2grid-id-display&quot;: 86}, {&quot;data-SMILES&quot;: &quot;C[C@@H](O)[C@H](N)C(=O)NC(=O)c1ncc[nH]c1=O&quot;, &quot;mols2grid-id&quot;: 87, &quot;data-Name&quot;: &quot;8657_895103&quot;, &quot;data-img&quot;: null, &quot;data-mols2grid-id-display&quot;: 87}, {&quot;data-SMILES&quot;: &quot;NC(=O)[C@H](N)CCC(=O)NC(=O)c1ncc[nH]c1=O&quot;, &quot;mols2grid-id&quot;: 88, &quot;data-Name&quot;: &quot;8657_2560808&quot;, &quot;data-img&quot;: null, &quot;data-mols2grid-id-display&quot;: 88}, {&quot;data-SMILES&quot;: &quot;NCC(=O)NCCC(=O)NC(=O)c1ncc[nH]c1=O&quot;, &quot;mols2grid-id&quot;: 89, &quot;data-Name&quot;: &quot;8657_1637970&quot;, &quot;data-img&quot;: null, &quot;data-mols2grid-id-display&quot;: 89}, {&quot;data-SMILES&quot;: &quot;N=C(N)NC[C@@H](N)C(=O)N[C@H](CO)C(=O)O&quot;, &quot;mols2grid-id&quot;: 90, &quot;data-Name&quot;: &quot;895342_1576365&quot;, &quot;data-img&quot;: null, &quot;data-mols2grid-id-display&quot;: 90}, {&quot;data-SMILES&quot;: &quot;CN(C)C[C@@H](N)C(=O)N[C@H](CO)C(=O)O&quot;, &quot;mols2grid-id&quot;: 91, &quot;data-Name&quot;: &quot;895342_35024242&quot;, &quot;data-img&quot;: null, &quot;data-mols2grid-id-display&quot;: 91}, {&quot;data-SMILES&quot;: &quot;Nc1nnn(CC(=O)N[C@H](CO)C(=O)O)n1&quot;, &quot;mols2grid-id&quot;: 92, &quot;data-Name&quot;: &quot;895342_4294607&quot;, &quot;data-img&quot;: null, &quot;data-mols2grid-id-display&quot;: 92}, {&quot;data-SMILES&quot;: &quot;COC(=O)[C@@H](O)CC(=O)N[C@H](CO)C(=O)O&quot;, &quot;mols2grid-id&quot;: 93, &quot;data-Name&quot;: &quot;895342_14585673&quot;, &quot;data-img&quot;: null, &quot;data-mols2grid-id-display&quot;: 93}, {&quot;data-SMILES&quot;: &quot;N=C(N)NC[C@H](N)C(=O)N[C@H](CO)C(=O)O&quot;, &quot;mols2grid-id&quot;: 94, &quot;data-Name&quot;: &quot;895342_2384694&quot;, &quot;data-img&quot;: null, &quot;data-mols2grid-id-display&quot;: 94}, {&quot;data-SMILES&quot;: &quot;N[C@H](CO)C(=O)N[C@H](CO)C(=O)O&quot;, &quot;mols2grid-id&quot;: 95, &quot;data-Name&quot;: &quot;895342_895342&quot;, &quot;data-img&quot;: null, &quot;data-mols2grid-id-display&quot;: 95}, {&quot;data-SMILES&quot;: &quot;NCC[C@H](N)C(=O)N[C@H](CO)C(=O)O&quot;, &quot;mols2grid-id&quot;: 96, &quot;data-Name&quot;: &quot;895342_52986906&quot;, &quot;data-img&quot;: null, &quot;data-mols2grid-id-display&quot;: 96}, {&quot;data-SMILES&quot;: &quot;C[C@@H](O)[C@H](N)C(=O)N[C@H](CO)C(=O)O&quot;, &quot;mols2grid-id&quot;: 97, &quot;data-Name&quot;: &quot;895342_895103&quot;, &quot;data-img&quot;: null, &quot;data-mols2grid-id-display&quot;: 97}, {&quot;data-SMILES&quot;: &quot;NC(=O)[C@H](N)CCC(=O)N[C@H](CO)C(=O)O&quot;, &quot;mols2grid-id&quot;: 98, &quot;data-Name&quot;: &quot;895342_2560808&quot;, &quot;data-img&quot;: null, &quot;data-mols2grid-id-display&quot;: 98}, {&quot;data-SMILES&quot;: &quot;NCC(=O)NCCC(=O)N[C@H](CO)C(=O)O&quot;, &quot;mols2grid-id&quot;: 99, &quot;data-Name&quot;: &quot;895342_1637970&quot;, &quot;data-img&quot;: null, &quot;data-mols2grid-id-display&quot;: 99}]);\n",
       "\n",
       "\n",
       "// filter\n",
       "if (window.parent.mols2grid_lists === undefined) {\n",
       "    window.parent.mols2grid_lists = {};\n",
       "}\n",
       "window.parent.mols2grid_lists[&quot;default&quot;] = listObj;\n",
       "\n",
       "\n",
       "// selection\n",
       "class MolStorage extends Map {\n",
       "    multi_set(_id, _smiles) {\n",
       "        for (let i = 0; i &lt; _id.length; i++) {\n",
       "            this.set(_id[i], _smiles[i])\n",
       "        }\n",
       "    }\n",
       "    multi_del(_id) {\n",
       "        for (let i = 0; i &lt; _id.length; i++) {\n",
       "            this.delete(_id[i])\n",
       "        }\n",
       "    }\n",
       "    to_dict() {\n",
       "        var content = &#x27;{&#x27;\n",
       "        for (let [key, value] of this) {\n",
       "            content += key + &#x27;:&#x27; + JSON.stringify(value) + &#x27;,&#x27;\n",
       "        }\n",
       "        content = content.length &gt; 1 ? content.slice(0, -1) : content\n",
       "        content += &#x27;}&#x27;\n",
       "        return content\n",
       "    }\n",
       "    to_keys() {\n",
       "        var content = []\n",
       "        for (let [key] of this) {\n",
       "            content.push(key)\n",
       "        }\n",
       "        return content\n",
       "    }\n",
       "    download_smi(fileName, allItems) {\n",
       "        var content = &#x27;&#x27;\n",
       "\n",
       "        if (allItems) {\n",
       "            // Gather all smiles\n",
       "            for (var item of allItems) {\n",
       "                var smiles = item.values()[&#x27;data-SMILES&#x27;]\n",
       "                var id = item.values()[&#x27;mols2grid-id&#x27;]\n",
       "                content += smiles + &#x27; &#x27; + id + &#x27;\\n&#x27;\n",
       "            }\n",
       "        } else {\n",
       "            // Gather selected smiles\n",
       "            for (let [key, value] of this) {\n",
       "                content += value + &#x27; &#x27; + key + &#x27;\\n&#x27;\n",
       "            }\n",
       "        }\n",
       "\n",
       "        var a = document.createElement(&#x27;a&#x27;)\n",
       "        var file = new Blob([content], { type: &#x27;text/plain&#x27; })\n",
       "        a.href = URL.createObjectURL(file)\n",
       "        a.download = fileName\n",
       "        a.click()\n",
       "        a.remove()\n",
       "    }\n",
       "}\n",
       "var SELECTION = new MolStorage();\n",
       "\n",
       "\n",
       "\n",
       "// kernel\n",
       "function add_selection(grid_id, _id, smiles) {\n",
       "    SELECTION.multi_set(_id, smiles);\n",
       "    let model = window.parent[&quot;_MOLS2GRID_&quot; + grid_id];\n",
       "    if (model) {\n",
       "        model.set(&quot;selection&quot;, SELECTION.to_dict());\n",
       "        model.save_changes();\n",
       "    }\n",
       "}\n",
       "function del_selection(grid_id, _id) {\n",
       "    SELECTION.multi_del(_id);\n",
       "    let model = window.parent[&quot;_MOLS2GRID_&quot; + grid_id];\n",
       "    if (model) {\n",
       "        model.set(&quot;selection&quot;, SELECTION.to_dict());\n",
       "        model.save_changes();\n",
       "    }\n",
       "}\n",
       "if (window.parent.IPython !== undefined) {\n",
       "    // Jupyter notebook\n",
       "    var kernel_env = &quot;jupyter&quot;;\n",
       "} else if (window.parent.google !== undefined) {\n",
       "    // Google colab\n",
       "    var kernel_env = &quot;colab&quot;;\n",
       "} else {\n",
       "    var kernel_env = null;\n",
       "}\n",
       "\n",
       "\n",
       "\n",
       "\n",
       "// sort\n",
       "var sortField = &#x27;mols2grid-id&#x27;\n",
       "var sortOrder = &#x27;asc&#x27;\n",
       "\n",
       "// Sort dropdown\n",
       "$(&#x27;#mols2grid .m2g-sort select&#x27;).change(sort)\n",
       "\n",
       "// Sort order\n",
       "$(&#x27;#mols2grid .m2g-order&#x27;).click(flipSort)\n",
       "\n",
       "function sort(e) {\n",
       "    if (e) {\n",
       "        sortField = e.target.value\n",
       "        var selectedOption = e.target.options[e.target.selectedIndex]\n",
       "        var sortFieldDisplay = selectedOption.text\n",
       "    }\n",
       "\n",
       "    // Sort\n",
       "    if (sortField == &#x27;checkbox&#x27;) {\n",
       "        listObj.sort(&#x27;mols2grid-id&#x27;, {order: sortOrder, sortFunction: checkboxSort})\n",
       "    } else {\n",
       "        listObj.sort(sortField, {order: sortOrder, sortFunction: mols2gridSortFunction})\n",
       "    }\n",
       "\n",
       "    // Update UI.\n",
       "    $(this).parent().find(&#x27;.m2g-display&#x27;).text(sortFieldDisplay)\n",
       "}\n",
       "\n",
       "// prettier-ignore\n",
       "function flipSort() {\n",
       "    $(this).parent().removeClass(&#x27;m2d-arrow-&#x27; + sortOrder)\n",
       "    sortOrder = sortOrder === &#x27;desc&#x27; ? &#x27;asc&#x27; : &#x27;desc&#x27;\n",
       "    $(this).parent().addClass(&#x27;m2d-arrow-&#x27; + sortOrder)\n",
       "    sort()\n",
       "}\n",
       "\n",
       "function mols2gridSortFunction(itemA, itemB, options) {\n",
       "    var x = itemA.values()[options.valueName]\n",
       "    var y = itemB.values()[options.valueName]\n",
       "    if (typeof x === &#x27;number&#x27;) {\n",
       "        if (isFinite(x - y)) {\n",
       "            return x - y\n",
       "        } else {\n",
       "            return isFinite(x) ? -1 : 1\n",
       "        }\n",
       "    } else {\n",
       "        x = x ? x.toLowerCase() : x\n",
       "        y = y ? y.toLowerCase() : y\n",
       "        return x &lt; y ? -1 : x &gt; y ? 1 : 0\n",
       "    }\n",
       "}\n",
       "function checkboxSort(itemA, itemB, options) {\n",
       "    if (itemA.elm !== undefined) {\n",
       "        var checkedA = itemA.elm.querySelector(&#x27;input[type=checkbox]&#x27;).checked\n",
       "        if (itemB.elm !== undefined) {\n",
       "            var checkedB = itemB.elm.querySelector(&#x27;input[type=checkbox]&#x27;).checked\n",
       "            if (checkedA &amp;&amp; !checkedB) {\n",
       "                return -1\n",
       "            } else if (!checkedA &amp;&amp; checkedB) {\n",
       "                return 1\n",
       "            } else {\n",
       "                return 0\n",
       "            }\n",
       "        } else {\n",
       "            return -1\n",
       "        }\n",
       "    } else if (itemB.elm !== undefined) {\n",
       "        return 1\n",
       "    } else {\n",
       "        return 0\n",
       "    }\n",
       "}\n",
       "\n",
       "\n",
       "\n",
       "\n",
       "\n",
       "// grid interactions (select, click, tooltip, key events)\n",
       "// Check if selection UI is supported.\n",
       "var supportSelection = eval(&#x27;True&#x27;.toLowerCase());\n",
       "\n",
       "listObj.on(&quot;updated&quot;, initInteraction);\n",
       "\n",
       "// (Re)initialiuze all grid interaction every time the grid changes.\n",
       "function initInteraction(list) {\n",
       "    initCellClick()\n",
       "    initToolTip()\n",
       "    initKeyboard()\n",
       "    if (supportSelection) initCheckbox()\n",
       "\n",
       "\n",
       "    // Hide pagination if there is only one page.\n",
       "    if (listObj.matchingItems.length &lt;= listObj.page) {\n",
       "        $(&#x27;#mols2grid .m2g-pagination&#x27;).hide()\n",
       "    } else {\n",
       "        $(&#x27;#mols2grid .m2g-pagination&#x27;).show()\n",
       "    }\n",
       "\n",
       "    // Add a bunch of phantom cells.\n",
       "    // These are used as filler to make sure that\n",
       "    // no grid cells need to be resized when there&#x27;s\n",
       "    // not enough results to fill the row.\n",
       "    $(&#x27;#mols2grid .m2g-list&#x27;).append(&#x27;&lt;div class=&quot;m2g-cell m2g-phantom&quot;&gt;&lt;/div&gt;&#x27;.repeat(11));\n",
       "}\n",
       "\n",
       "// Cell click handler.\n",
       "function initCellClick() {\n",
       "    $(&#x27;#mols2grid .m2g-cell&#x27;).off(&#x27;click&#x27;).click(function(e) {\n",
       "        if ($(e.target).hasClass(&#x27;m2g-info&#x27;) || $(e.target).is(&#x27;:checkbox&#x27;)) {\n",
       "            // Info button / Checkbox --&gt; do nothing.\n",
       "        } else if ($(e.target).is(&#x27;div&#x27;) &amp;&amp; $(e.target).hasClass(&#x27;data&#x27;)) {\n",
       "            // Data string --&gt; copy text.\n",
       "            copyOnClick(e.target)\n",
       "        } else if ($(e.target).hasClass(&#x27;m2g-callback&#x27;)) {\n",
       "            // Callback button.\n",
       "            onCallbackButtonClick(e.target)\n",
       "        } else {\n",
       "            // Outside checkbox --&gt; toggle the checkbox.\n",
       "            if (supportSelection) {\n",
       "                var chkbox = $(this).find(&#x27;input:checkbox&#x27;)[0]\n",
       "                chkbox.checked = !chkbox.checked\n",
       "                $(chkbox).trigger(&#x27;change&#x27;)\n",
       "            }\n",
       "        }\n",
       "    })\n",
       "}\n",
       "\n",
       "// Store an element&#x27;s text content in the clipboard.\n",
       "function copyOnClick(target) {\n",
       "    var text = $(target).text()\n",
       "    navigator.clipboard.writeText(text)\n",
       "\n",
       "    // Blink the cell to indicate that the text was copied.\n",
       "    $(target).addClass(&#x27;m2g-copy-blink&#x27;)\n",
       "    setTimeout(function() {\n",
       "        $(target).removeClass(&#x27;m2g-copy-blink&#x27;)\n",
       "    }, 450)\n",
       "}\n",
       "\n",
       "// Keyboard actions.\n",
       "function initKeyboard() {\n",
       "    // Disable scroll when pressing UP/DOWN arrows\n",
       "    $(&#x27;#mols2grid .m2g-cell&#x27;).off(&#x27;keydown&#x27;).keydown(function(e) {\n",
       "        if (e.which == 38 || e.which == 40) {\n",
       "            e.preventDefault()\n",
       "        }\n",
       "    })\n",
       "\n",
       "    $(&#x27;#mols2grid .m2g-cell&#x27;).off(&#x27;keyup&#x27;).keyup(function(e) {\n",
       "        var chkbox = $(this).find(&#x27;input:checkbox&#x27;)[0]\n",
       "        if (e.which == 13) {\n",
       "            // ENTER: toggle\n",
       "            chkbox.checked = !chkbox.checked\n",
       "            $(chkbox).trigger(&#x27;change&#x27;)\n",
       "        } else if (e.which == 27 || e.which == 8) {\n",
       "            // ESC/BACKSPACE: unselect\n",
       "            chkbox.checked = false\n",
       "            $(chkbox).trigger(&#x27;change&#x27;)\n",
       "        } else if (e.which == 37) {\n",
       "            // LEFT\n",
       "            $(this).prev().focus()\n",
       "        } else if (e.which == 39) {\n",
       "            // RIGHT\n",
       "            $(this).next().focus()\n",
       "        } else if (e.which == 38 || e.which == 40) {\n",
       "            var containerWidth = $(this).parent().outerWidth()\n",
       "            var cellWidth = $(this).outerWidth() + parseInt($(this).css(&#x27;marginLeft&#x27;)) * 2\n",
       "            var columns = Math.round(containerWidth / cellWidth)\n",
       "            var index = $(this).index()\n",
       "            if (e.which == 38) {\n",
       "                // UP\n",
       "                var indexAbove = Math.max(index - columns, 0)\n",
       "                $(this).parent().children().eq(indexAbove).focus()\n",
       "            } else if (e.which == 40) {\n",
       "                // DOWN    \n",
       "                var total = $(this).parent().children().length\n",
       "                var indexBelow = Math.min(index + columns, total)\n",
       "                $(this).parent().children().eq(indexBelow).focus()\n",
       "            }\n",
       "        }\n",
       "    })\n",
       "}\n",
       "\n",
       "// Show tooltip when hovering the info icon.\n",
       "function initToolTip() {\n",
       "    $(&#x27;#mols2grid .m2g-info&#x27;).off(&#x27;mouseenter&#x27;).off(&#x27;mouseleave&#x27;).off(&#x27;click&#x27;).mouseenter(function() {\n",
       "        // Show on enter\n",
       "        $(this).closest(&#x27;.m2g-cell&#x27;).find(&#x27;.m2g-tooltip[data-toggle=&quot;popover&quot;]&#x27;).popover(&#x27;show&#x27;)\n",
       "        $(&#x27;body &gt; .popover&#x27;).click(function(e) {\n",
       "            if ($(e.target).hasClass(&#x27;copy-me&#x27;)) {\n",
       "                copyOnClick(e.target)\n",
       "            } else if ($(e.target).is(&#x27;button&#x27;)) {\n",
       "                \n",
       "            }\n",
       "        })\n",
       "    }).mouseleave(function() {\n",
       "        // Hide on leave, unless sticky.\n",
       "        if (!$(this).closest(&#x27;.m2g-cell&#x27;).hasClass(&#x27;m2g-keep-tooltip&#x27;)) {\n",
       "            $(this).closest(&#x27;.m2g-cell&#x27;).find(&#x27;.m2g-tooltip[data-toggle=&quot;popover&quot;]&#x27;).popover(&#x27;hide&#x27;)\n",
       "        }\n",
       "    }).click(function() {\n",
       "        // Toggle sticky on click.\n",
       "        $(this).closest(&#x27;.m2g-cell&#x27;).toggleClass(&#x27;m2g-keep-tooltip&#x27;)\n",
       "\n",
       "        // Hide tooltip when sticky was turned off.\n",
       "        if ($(this).closest(&#x27;.m2g-cell&#x27;).hasClass(&#x27;m2g-keep-tooltip&#x27;)) {\n",
       "            $(this).closest(&#x27;.m2g-cell&#x27;).find(&#x27;.m2g-tooltip[data-toggle=&quot;popover&quot;]&#x27;).popover(&#x27;show&#x27;)\n",
       "        } else if (!$(this).closest(&#x27;.m2g-cell&#x27;).hasClass(&#x27;m2g-keep-tooltip&#x27;)) {\n",
       "            $(this).closest(&#x27;.m2g-cell&#x27;).find(&#x27;.m2g-tooltip[data-toggle=&quot;popover&quot;]&#x27;).popover(&#x27;hide&#x27;)\n",
       "        }\n",
       "    })\n",
       "}\n",
       "\n",
       "// Update selection on checkbox click.\n",
       "function initCheckbox() {\n",
       "    $(&quot;input:checkbox&quot;).off(&#x27;change&#x27;).change(function() {\n",
       "        var _id = parseInt($(this).closest(&quot;.m2g-cell&quot;).attr(&quot;data-mols2grid-id&quot;));\n",
       "        if (this.checked) {\n",
       "            var _smiles = $($(this).closest(&quot;.m2g-cell&quot;).children(&quot;.data-SMILES&quot;)[0]).text();\n",
       "            add_selection(&quot;default&quot;, [_id], [_smiles]);\n",
       "        } else {\n",
       "            del_selection(&quot;default&quot;, [_id]);\n",
       "        }\n",
       "    });\n",
       "}\n",
       "\n",
       "// Callback button\n",
       "function onCallbackButtonClick(target) {\n",
       "    var data = {}\n",
       "    data[&quot;mols2grid-id&quot;] = parseInt($(target).closest(&quot;.m2g-cell&quot;)\n",
       "                                            .attr(&quot;data-mols2grid-id&quot;));\n",
       "    data[&quot;img&quot;] = $(target).parent().siblings(&quot;.data-img&quot;).eq(0).get(0).innerHTML;\n",
       "    $(target).parent().siblings(&quot;.data&quot;).not(&quot;.data-img&quot;).each(function() {\n",
       "        let name = this.className.split(&quot; &quot;)\n",
       "            .filter(cls =&gt; cls.startsWith(&quot;data-&quot;))[0]\n",
       "            .substring(5);\n",
       "        data[name] = this.innerHTML;\n",
       "    });\n",
       "\n",
       "    \n",
       "    // Call custom js callback.\n",
       "    None\n",
       "    \n",
       "}\n",
       "\n",
       "\n",
       "\n",
       "/**\n",
       " * Actions\n",
       " */\n",
       "\n",
       "// Listen to action dropdown.\n",
       "$(&#x27;#mols2grid .m2g-actions select&#x27;).change(function(e) {\n",
       "    var val = e.target.value\n",
       "    switch(val) {\n",
       "        case &#x27;select-all&#x27;:\n",
       "            selectAll()\n",
       "            break\n",
       "        case &#x27;select-matching&#x27;:\n",
       "            selectMatching()\n",
       "            break\n",
       "        case &#x27;unselect-all&#x27;:\n",
       "            unselectAll()\n",
       "            break\n",
       "        case &#x27;invert&#x27;:\n",
       "            invertSelection()\n",
       "            break\n",
       "        case &#x27;copy&#x27;:\n",
       "            copy()\n",
       "            break\n",
       "        case &#x27;save-smiles&#x27;:\n",
       "            saveSmiles()\n",
       "            break\n",
       "        case &#x27;save-csv&#x27;:\n",
       "            saveCSV()\n",
       "            break\n",
       "    }\n",
       "    $(this).val(&#x27;&#x27;) // Reset dropdown\n",
       "})\n",
       "\n",
       "// Check all.\n",
       "function selectAll(e) {\n",
       "    var _id = [];\n",
       "    var _smiles = [];\n",
       "    listObj.items.forEach(function (item) {\n",
       "        if (item.elm) {\n",
       "            item.elm.getElementsByTagName(&quot;input&quot;)[0].checked = true;\n",
       "        } else {\n",
       "            item.show()\n",
       "            item.elm.getElementsByTagName(&quot;input&quot;)[0].checked = true;\n",
       "            item.hide()\n",
       "        }\n",
       "        _id.push(item.values()[&quot;mols2grid-id&quot;]);\n",
       "        _smiles.push(item.values()[&quot;data-SMILES&quot;]);\n",
       "    });\n",
       "    add_selection(&quot;default&quot;, _id, _smiles);\n",
       "};\n",
       "\n",
       "\n",
       "// Check matching.\n",
       "function selectMatching(e) {\n",
       "    var _id = [];\n",
       "    var _smiles = [];\n",
       "    listObj.matchingItems.forEach(function (item) {\n",
       "        if (item.elm) {\n",
       "            item.elm.getElementsByTagName(&quot;input&quot;)[0].checked = true;\n",
       "        } else {\n",
       "            item.show()\n",
       "            item.elm.getElementsByTagName(&quot;input&quot;)[0].checked = true;\n",
       "            item.hide()\n",
       "        }\n",
       "        _id.push(item.values()[&quot;mols2grid-id&quot;]);\n",
       "        _smiles.push(item.values()[&quot;data-SMILES&quot;]);\n",
       "    });\n",
       "    add_selection(&quot;default&quot;, _id, _smiles);\n",
       "};\n",
       "\n",
       "// Uncheck all.\n",
       "function unselectAll(e) {\n",
       "    var _id = [];\n",
       "    listObj.items.forEach(function (item) {\n",
       "        if (item.elm) {\n",
       "            item.elm.getElementsByTagName(&quot;input&quot;)[0].checked = false;\n",
       "        } else {\n",
       "            item.show()\n",
       "            item.elm.getElementsByTagName(&quot;input&quot;)[0].checked = false;\n",
       "            item.hide()\n",
       "        }\n",
       "        _id.push(item.values()[&quot;mols2grid-id&quot;]);\n",
       "    });\n",
       "    del_selection(&quot;default&quot;, _id);\n",
       "};\n",
       "\n",
       "// Invert selection.\n",
       "function invertSelection(e) {\n",
       "    var _id_add = [];\n",
       "    var _id_del = [];\n",
       "    var _smiles = [];\n",
       "    listObj.items.forEach(function (item) {\n",
       "        if (item.elm) {\n",
       "            var chkbox = item.elm.getElementsByTagName(&quot;input&quot;)[0]\n",
       "            chkbox.checked = !chkbox.checked;\n",
       "        } else {\n",
       "            item.show()\n",
       "            var chkbox = item.elm.getElementsByTagName(&quot;input&quot;)[0]\n",
       "            chkbox.checked = !chkbox.checked;\n",
       "            item.hide()\n",
       "        }\n",
       "        if (chkbox.checked) {\n",
       "            _id_add.push(item.values()[&quot;mols2grid-id&quot;]);\n",
       "            _smiles.push(item.values()[&quot;data-SMILES&quot;]);\n",
       "        } else {\n",
       "            _id_del.push(item.values()[&quot;mols2grid-id&quot;]);\n",
       "        }\n",
       "    });\n",
       "    del_selection(&quot;default&quot;, _id_del);\n",
       "    add_selection(&quot;default&quot;, _id_add, _smiles);\n",
       "};\n",
       "\n",
       "// Copy to clipboard.\n",
       "function copy(e) {\n",
       "    // navigator.clipboard.writeText(SELECTION.to_dict());\n",
       "    content = _renderCSV(&#x27;\\t&#x27;)\n",
       "    navigator.clipboard.writeText(content)\n",
       "};\n",
       "\n",
       "// Export smiles.\n",
       "function saveSmiles(e) {\n",
       "    var fileName = &quot;selection.smi&quot;\n",
       "    if (SELECTION.size) {\n",
       "        // Download selected smiles\n",
       "        SELECTION.download_smi(fileName);\n",
       "    } else {\n",
       "        // Download all smiles\n",
       "        SELECTION.download_smi(fileName, listObj.items);\n",
       "    }\n",
       "};\n",
       "\n",
       "// Export CSV.\n",
       "function saveCSV(e) {\n",
       "    content = _renderCSV(&#x27;;&#x27;)\n",
       "    var a = document.createElement(&quot;a&quot;);\n",
       "    var file = new Blob([content], {type: &quot;text/csv&quot;});\n",
       "    a.href = URL.createObjectURL(file);\n",
       "    a.download = &quot;selection.csv&quot;;\n",
       "    a.click();\n",
       "    a.remove();\n",
       "};\n",
       "\n",
       "// Render CSV for export of clipboard.\n",
       "function _renderCSV(sep) {\n",
       "    // Same order as subset + tooltip\n",
       "    var columns = Array.from(listObj.items[0].elm.querySelectorAll(&quot;div.data&quot;))\n",
       "        .map(elm =&gt; elm.classList[1])\n",
       "        .filter(name =&gt; name !== &quot;data-img&quot;);\n",
       "    // Remove &#x27;data-&#x27; and img\n",
       "    var header = columns.map(name =&gt; name.slice(5));\n",
       "    // CSV content\n",
       "    header = [&quot;index&quot;].concat(header).join(sep);\n",
       "    var content = header + &quot;\\n&quot;;\n",
       "    listObj.items.forEach(function (item) {\n",
       "        let data = item.values();\n",
       "        let index = data[&quot;mols2grid-id&quot;];\n",
       "        if (SELECTION.has(index) || SELECTION.size === 0) {\n",
       "            content += index;\n",
       "            columns.forEach((key) =&gt; {\n",
       "                content += sep + data[key];\n",
       "            })\n",
       "            content += &quot;\\n&quot;;\n",
       "        }\n",
       "    });\n",
       "    return content\n",
       "}\n",
       "\n",
       "\n",
       "// generate images for the currently displayed molecules\n",
       "var draw_opts = {&quot;width&quot;: 130, &quot;height&quot;: 90};\n",
       "var json_draw_opts = JSON.stringify(draw_opts);\n",
       "\n",
       "var smarts_matches = {};\n",
       "\n",
       "// Load RDKit\n",
       "window\n",
       ".initRDKitModule()\n",
       ".then(function(RDKit) {\n",
       "    console.log(&#x27;RDKit version: &#x27;, RDKit.version());\n",
       "    window.RDKit = RDKit;\n",
       "    window.RDKitModule = RDKit;\n",
       "\n",
       "    // Searchbar\n",
       "    function SmartsSearch(query, columns) {\n",
       "    var smiles_col = columns[0];\n",
       "    smarts_matches = {};\n",
       "    var query = $(&#x27;#mols2grid .m2g-searchbar&#x27;).val();\n",
       "    var qmol = RDKit.get_qmol(query);\n",
       "    if (qmol.is_valid()) {\n",
       "        listObj.items.forEach(function (item) {\n",
       "            var smiles = item.values()[smiles_col]\n",
       "            var mol = RDKit.get_mol(smiles, &#x27;{&quot;removeHs&quot;: false }&#x27;);\n",
       "            if (mol.is_valid()) {\n",
       "                var results = mol.get_substruct_matches(qmol);\n",
       "                if (results === &quot;\\{\\}&quot;) {\n",
       "                    item.found = false;\n",
       "                } else {\n",
       "                    item.found = true;\n",
       "                    \n",
       "                    results = JSON.parse(results);\n",
       "                    \n",
       "                    var highlights = {&quot;atoms&quot;: [], &quot;bonds&quot;: []};\n",
       "                    results.forEach(function (match) {\n",
       "                        highlights[&quot;atoms&quot;].push(...match.atoms)\n",
       "                        highlights[&quot;bonds&quot;].push(...match.bonds)\n",
       "                    });\n",
       "                    \n",
       "                    var index = item.values()[&quot;mols2grid-id&quot;];\n",
       "                    smarts_matches[index] = highlights;\n",
       "                    \n",
       "                }\n",
       "            } else {\n",
       "                item.found = false;\n",
       "            }\n",
       "            mol.delete();\n",
       "        });\n",
       "    }\n",
       "    qmol.delete();\n",
       "}\n",
       "var search_type = &quot;Text&quot;;\n",
       "// Temporary fix for regex characters being escaped by list.js\n",
       "// This extends String.replace to ignore the regex pattern used by list.js and returns\n",
       "// the string unmodified. Other calls should not be affected, unless they use the exact\n",
       "// same pattern and replacement value.\n",
       "// TODO: remove once the issue is fixed in list.js and released\n",
       "String.prototype.replace = (function(_super) {\n",
       "    return function() {\n",
       "        if (\n",
       "            (arguments[0].toString() === &#x27;/[-[\\\\]{}()*+?.,\\\\\\\\^$|#]/g&#x27;)\n",
       "            &amp;&amp; (arguments[1] === &#x27;\\\\$&amp;&#x27;)\n",
       "        ) {\n",
       "            if (this.length === 0) {\n",
       "                return &#x27;&#x27;\n",
       "            }\n",
       "            return this\n",
       "        }\n",
       "        return _super.apply(this, arguments);\n",
       "    };         \n",
       "})(String.prototype.replace);\n",
       "\n",
       "// Switch search type (Text or SMARTS)\n",
       "$(&#x27;#mols2grid .m2g-search-options .m2g-option&#x27;).click(function() {\n",
       "    search_type = $(this).text();\n",
       "    $(&#x27;#mols2grid .m2g-search-options .m2g-option.sel&#x27;).removeClass(&quot;sel&quot;);\n",
       "    $(this).addClass(&quot;sel&quot;);\n",
       "});\n",
       "\n",
       "// Searchbar update event handler\n",
       "$(&#x27;#mols2grid .m2g-searchbar&#x27;).on(&quot;keyup&quot;, function(e) {\n",
       "    var query = e.target.value;\n",
       "    if (search_type === &quot;Text&quot;) {\n",
       "        smarts_matches = {};\n",
       "        listObj.search(query, [&#x27;data-mols2grid-id&#x27;, &#x27;data-Name&#x27;]);\n",
       "    } else {\n",
       "        listObj.search(query, [&quot;data-SMILES&quot;], SmartsSearch);\n",
       "    }\n",
       "});\n",
       "\n",
       "    \n",
       "    // Generate images for the currently displayed molecules.\n",
       "RDKit.prefer_coordgen(true);\n",
       "function draw_mol(smiles, index, template_mol) {\n",
       "    var mol = RDKit.get_mol(smiles, &#x27;{&quot;removeHs&quot;: false }&#x27;);\n",
       "    var svg = &quot;&quot;;\n",
       "    if (mol.is_valid()) {\n",
       "        var highlights = smarts_matches[index];\n",
       "        if (highlights) {\n",
       "            var details = Object.assign({}, draw_opts, highlights);\n",
       "            details = JSON.stringify(details);\n",
       "            mol.generate_aligned_coords(template_mol, true);\n",
       "        } else {\n",
       "            var details = json_draw_opts;\n",
       "        }\n",
       "        svg = mol.get_svg_with_highlights(details);\n",
       "    }\n",
       "    mol.delete();\n",
       "    if (svg == &quot;&quot;) {\n",
       "        return &#x27;&lt;svg width=&quot;130&quot; height=&quot;90&quot; xmlns=&quot;http://www.w3.org/2000/svg&quot; version=&quot;1.1&quot; viewBox=&quot;0 0 130 90&quot;&gt;&lt;/svg&gt;&#x27;;\n",
       "    }\n",
       "    return svg;\n",
       "}\n",
       "\n",
       "// Update images when the list is updated.\n",
       "listObj.on(&quot;updated&quot;, function (list) {\n",
       "    var query = $(&#x27;#mols2grid .m2g-searchbar&#x27;).val();\n",
       "    var template_mol;\n",
       "    if (query === &quot;&quot;) {\n",
       "        smarts_matches = {};\n",
       "        template_mol = null;\n",
       "    } else {\n",
       "        template_mol = RDKit.get_qmol(query);\n",
       "        template_mol.set_new_coords(true);\n",
       "    }\n",
       "    $(&#x27;#mols2grid .m2g-cell&#x27;).each(function() {\n",
       "        var $t = $(this);\n",
       "        var smiles = $t.children(&quot;.data-SMILES&quot;).first().text();\n",
       "        var index = parseInt(this.getAttribute(&quot;data-mols2grid-id&quot;));\n",
       "        var svg = draw_mol(smiles, index, template_mol);\n",
       "        $t.children(&quot;.data-img&quot;).html(svg);\n",
       "    });\n",
       "    if (template_mol) {\n",
       "        template_mol.delete();\n",
       "    }\n",
       "});\n",
       "    \n",
       "\n",
       "    // Trigger update to activate tooltips, draw images, setup callbacks...\n",
       "    listObj.update();\n",
       "    \n",
       "    // Set iframe height to fit content.\n",
       "    fitIframe(window.frameElement);\n",
       "});\n",
       "        &lt;/script&gt;\n",
       "\n",
       "\n",
       "\n",
       "\n",
       "    &lt;/body&gt;\n",
       "&lt;/html&gt;\n",
       "\">\n",
       "</iframe>"
      ],
      "text/plain": [
       "<IPython.core.display.HTML object>"
      ]
     },
     "execution_count": 16,
     "metadata": {},
     "output_type": "execute_result"
    }
   ],
   "source": [
    "mols2grid.display(prod_df,subset=[\"img\",\"Name\"])"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": null,
   "id": "5d7a1266",
   "metadata": {},
   "outputs": [],
   "source": []
  },
  {
   "cell_type": "code",
   "execution_count": null,
   "id": "63ffcffe",
   "metadata": {},
   "outputs": [],
   "source": []
  }
 ],
 "metadata": {
  "kernelspec": {
   "display_name": "Python 3 (ipykernel)",
   "language": "python",
   "name": "python3"
  },
  "language_info": {
   "codemirror_mode": {
    "name": "ipython",
    "version": 3
   },
   "file_extension": ".py",
   "mimetype": "text/x-python",
   "name": "python",
   "nbconvert_exporter": "python",
   "pygments_lexer": "ipython3",
   "version": "3.11.3"
  }
 },
 "nbformat": 4,
 "nbformat_minor": 5
}
